Refactor how Gr handles vertex and index data. GrGpu and GrInOrderDrawBuffer both GrBufferAllocPool to manage reserved and set-to-array vertex and index data.

rietveld issue 4188049

git-svn-id: http://skia.googlecode.com/svn/trunk@786 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrConfig.h b/gpu/include/GrConfig.h
index ff694da..7805074 100644
--- a/gpu/include/GrConfig.h
+++ b/gpu/include/GrConfig.h
@@ -84,7 +84,7 @@
         #undef GR_LINUX_BUILD
         #define GR_LINUX_BUILD      1
 //      #error "LINUX"
-    #endif    
+    #endif
 #endif
 
 // we need both GR_DEBUG and GR_RELEASE to be defined as 0 or 1
@@ -121,10 +121,10 @@
 #include <stdint.h>
 
 /*
- *  The "user config" file can be empty, and everything should work. It is 
+ *  The "user config" file can be empty, and everything should work. It is
  *  meant to store a given platform/client's overrides of our guess-work.
  *
- *  A alternate user config file can be specified by defining 
+ *  A alternate user config file can be specified by defining
  *  GR_USER_CONFIG_FILE. It should be defined relative to GrConfig.h
  *
  *  e.g. it can specify GR_DEBUG/GR_RELEASE as it please, change the BUILD
@@ -132,7 +132,7 @@
  */
 #if !defined(GR_USER_CONFIG_FILE)
     #include "GrUserConfig.h"
-#else 
+#else
     #include GR_USER_CONFIG_FILE
 #endif
 
@@ -155,7 +155,7 @@
 #define GR_STRING_IMPL(X) #X
 
 /**
- *  GR_CONCAT concatenates X and Y  where each is expanded before 
+ *  GR_CONCAT concatenates X and Y  where each is expanded before
  *  contanenation if either contains macros.
  */
 #define GR_CONCAT(X,Y) GR_CONCAT_IMPL(X,Y)
@@ -167,8 +167,8 @@
 #define GR_FILE_AND_LINE_STR __FILE__ "(" GR_STRING(__LINE__) ") : "
 
 /**
- *  Compilers have different ways of issuing warnings. This macro 
- *  attempts to abstract them, but may need to be specialized for your 
+ *  Compilers have different ways of issuing warnings. This macro
+ *  attempts to abstract them, but may need to be specialized for your
  *  particular compiler.
  *  To insert compiler warnings use "#pragma message GR_WARN(<string>)"
  */
@@ -184,9 +184,9 @@
 #if !defined(GR_ALWAYSBREAK)
     #if     GR_WIN32_BUILD
         #define GR_ALWAYSBREAK __debugbreak()
-    #else 
+    #else
         // TODO: do other platforms really not have continuable breakpoints?
-        // sign extend for 64bit architectures to be sure this is 
+        // sign extend for 64bit architectures to be sure this is
         // in the high address range
         #define GR_ALWAYSBREAK *((int*)(int64_t)(int32_t)0xbeefcafe) = 0;
     #endif
@@ -240,7 +240,7 @@
 inline void GrCrash(const char* msg) { GrPrintf(msg); GrAlwaysAssert(false); }
 
 /**
- *  GR_DEBUGCODE compiles the code X in debug builds only 
+ *  GR_DEBUGCODE compiles the code X in debug builds only
  */
 #if !defined(GR_DEBUGCODE)
     #if GR_DEBUG
@@ -255,7 +255,7 @@
  *  it may print the message in the compiler log. Obviously, the condition must
  *  be evaluatable at compile time.
  */
-// VS 2010 and GCC compiled with c++0x or gnu++0x support the new 
+// VS 2010 and GCC compiled with c++0x or gnu++0x support the new
 // static_assert.
 #if !defined(GR_STATIC_ASSERT)
     #if (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__GXX_EXPERIMENTAL_CXX0X__) && __GXX_EXPERIMENTAL_CXX0X__)
@@ -278,7 +278,7 @@
 
 #if !defined(GR_TEXT_SCALAR_TYPE_IS_USHORT)
     #define GR_TEXT_SCALAR_TYPE_IS_USHORT  0
-#endif    
+#endif
 #if !defined(GR_TEXT_SCALAR_TYPE_IS_FLOAT)
     #define GR_TEXT_SCALAR_TYPE_IS_FLOAT   0
 #endif
@@ -310,13 +310,23 @@
 /**
  *  GR_AGGRESSIVE_SHADER_OPTS controls how aggressively shaders are optimized
  *  for special cases. On systems where program changes are expensive this
- *  may not be advantageous. Consecutive draws may no longer use the same 
+ *  may not be advantageous. Consecutive draws may no longer use the same
  *  program.
  */
 #if !defined(GR_AGGRESSIVE_SHADER_OPTS)
     #define GR_AGGRESSIVE_SHADER_OPTS 0
 #endif
 
+/**
+ * GR_GEOM_BUFFER_LOCK_THRESHOLD gives a threshold (in bytes) for when Gr should
+ * lock a GrGeometryBuffer to update its contents. It will use Lock() if the
+ * size of the udpated region is greater than the threshold. Otherwise it will
+ * use updateData() or updateSubData().
+ */
+#if !defined(GR_GEOM_BUFFER_LOCK_THRESHOLD)
+    #define GR_GEOM_BUFFER_LOCK_THRESHOLD (1 << 15)
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 // tail section:
 //
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index ccc045e..6b9c3f3 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -20,12 +20,13 @@
 #include "GrClip.h"

 #include "GrGpu.h"

 #include "GrTextureCache.h"

-#include "GrInOrderDrawBuffer.h"

-#include "GrVertexBufferAllocPool.h"

 #include "GrPaint.h"

 

 class GrFontCache;

 class GrPathIter;

+class GrVertexBufferAllocPool;

+class GrIndexBufferAllocPool;

+class GrInOrderDrawBuffer;

 

 class GrContext : public GrRefCnt {

 public:

@@ -236,21 +237,21 @@
      *  @param paint        describes how to color pixels.

      *  @param strokeWidth  If strokeWidth < 0, then the rect is filled, else

      *                      the rect is mitered stroked based on strokeWidth. If

-     *                      strokeWidth == 0, then the stroke is always a single 

+     *                      strokeWidth == 0, then the stroke is always a single

      *                      pixel thick.

-     *  @param matrix       Optional matrix applied to the rect. Applied before 

+     *  @param matrix       Optional matrix applied to the rect. Applied before

      *                      context's matrix or the paint's matrix.

      *  The rects coords are used to access the paint (through texture matrix)

      */

-    void drawRect(const GrPaint& paint, 

-                  const GrRect&, 

+    void drawRect(const GrPaint& paint,

+                  const GrRect&,

                   GrScalar strokeWidth = -1,

                   const GrMatrix* matrix = NULL);

 

     /**

      * Maps a rect of paint coordinates onto the a rect of destination

      * coordinates. Each rect can optionally be transformed. The srcRect

-     * is stretched over the dstRect. The dstRect is transformed by the 

+     * is stretched over the dstRect. The dstRect is transformed by the

      * context's matrix and the srcRect is transformed by the paint's matrix.

      * Additional optional matrices can be provided by parameters.

      *

@@ -453,8 +454,9 @@
     GrTextureCache* fTextureCache;

     GrFontCache*    fFontCache;

 

-    GrVertexBufferAllocPool fVBAllocPool;

-    GrInOrderDrawBuffer     fTextDrawBuffer;

+    GrVertexBufferAllocPool*    fTextVBAllocPool;

+    GrIndexBufferAllocPool*     fTextIBAllocPool;

+    GrInOrderDrawBuffer*        fTextDrawBuffer;

 

     GrContext(GrGpu* gpu);

 

diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index e7f37f1..88782f1 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -47,8 +47,6 @@
      * The presence or absence of texture coordinates for each stage in the
      * vertex layout indicates whether a stage is enabled or not.
      */
-
-    // Currently there is just one stage but this will be changed soon.
     enum {
         kNumStages = 2,
         kMaxTexCoords = kNumStages
@@ -479,6 +477,36 @@
     GR_STATIC_ASSERT(kHighVertexLayoutBit < (1 << 8*sizeof(GrVertexLayout)));
 
     /**
+     * There are three paths for specifying geometry (vertices and optionally
+     * indices) to the draw target. When indexed drawing the indices and vertices
+     * can be each use a different path.
+     *
+     * 1. Provide a cpu array (set*SourceToArray). This is useful when the
+     *    caller's client has already provided vertex data in a format
+     *    the time compatible with a GrVertexLayout. The array must contain the
+     *    data at set*SourceToArray is called. The source stays in effect for
+     *    drawIndexed & drawNonIndexed calls until set*SourceToArray is called
+     *    again or one of the other two paths is chosen.
+     *
+     * 2. Reserve and Lock. This is most useful when the caller has data it must
+     *    transform before drawing and will not likely render it again. The
+     *    caller requests that the draw target make room for some amount of
+     *    vertex and/or index data. The target provides ptrs to hold the data
+     *    data. The caller can write the data into the pts up until the first
+     *    drawIndexed or drawNonIndexed call. At this point the data is frozen
+     *    and the ptrs are no longer guaranteed to be valid. All subsequent
+     *    drawIndexed & drawNonIndexed calls will use this data until
+     *    releaseReserved geometry is called. This must be called before another
+     *    source is set.
+     *
+     * 3. Vertex and Index Buffers. This is most useful for geometry that will
+     *    be rendered multiple times. SetVertexSourceToBuffer &
+     *    SetIndexSourceToBuffer are used to set the buffer and subsequent
+     *    drawIndexed and drawNonIndexed calls use this source until another
+     *    source is set.
+     */
+
+    /**
      * Reserves space for vertices and/or indices. Draw target will use
      * reserved vertices / indices at next draw.
      *
@@ -491,14 +519,19 @@
      *          to be filled by caller. The next indexed draw will read from
      *          these indices.
      *
-     * If a client does not already have a vertex buffer or cpu arrays then this
-     * is the preferred way to allocate vertex/index array. It allows the
-     * subclass of GrDrawTarget to decide whether to put data in buffers, to
-     * group vertex data that uses the same state (e.g. for deferred rendering),
-     * etc.
+     * If a client does not already have a vertex buffer then this is the
+     * preferred way to allocate vertex/index array. It allows the subclass of
+     * GrDrawTarget to decide whether to put data in buffers, to group vertex
+     * data that uses the same state (e.g. for deferred rendering), etc.
      *
-     * This must be matched with a releaseReservedGeometry call after all
-     * draws that reference the reserved geometry data have been called.
+     * Following the first draw after reserveAndLockGeometry the ptrs returned
+     * by releaseReservedGeometry are no longer valid and the geometry data
+     * cannot be further modified. The contents that were put in the reserved
+     * space can be drawn by multiple draws, however.
+     *
+     * reserveAndLockGeometry must be matched with a releaseReservedGeometry
+     * call after all draws that reference the reserved geometry data have
+     * been called.
      *
      * AutoGeometryRelease can be used to automatically call the release.
      *
@@ -541,8 +574,8 @@
      * @return  true if target should be flushed based on the input values.
      */
     virtual bool geometryHints(GrVertexLayout vertexLayout,
-                               int32_t*       vertexCount,
-                               int32_t*       indexCount) const;
+                               int* vertexCount,
+                               int* indexCount) const;
 
     /**
      * Releases reserved vertex/index data from reserveAndLockGeometry().
@@ -550,21 +583,25 @@
     void releaseReservedGeometry();
 
     /**
-     * Sets source of vertex data for the next draw. Data does not have to be
-     * in the array until drawIndexed or drawNonIndexed.
+     * Sets source of vertex data for the next draw. Array must contain
+     * the vertex data when this is called.
      *
      * @param array         cpu array containing vertex data.
-     * @param vertexLayout  layout of the vertex data in the array.
+     * @param size          size of the vertex data.
+     * @param vertexCount   the number of vertices in the array.
      */
-    void setVertexSourceToArray(const void* array, GrVertexLayout vertexLayout);
+    void setVertexSourceToArray(GrVertexLayout vertexLayout,
+                                const void* vertexArray,
+                                int vertexCount);
 
     /**
-     * Sets source of index data for the next indexed draw. Data does not have
-     * to be in the array until drawIndexed or drawNonIndexed.
+     * Sets source of index data for the next indexed draw. Array must contain
+     * the indices when this is called.
      *
-     * @param array cpu array containing index data.
+     * @param array         cpu array containing index data.
+     * @param indexCount    the number of indices in the array.
      */
-    void setIndexSourceToArray(const void* array);
+    void setIndexSourceToArray(const void* indexArray, int indexCount);
 
     /**
      * Sets source of vertex data for the next draw. Data does not have to be
@@ -574,8 +611,8 @@
      *                      unlocked before draw call.
      * @param vertexLayout  layout of the vertex data in the buffer.
      */
-    void setVertexSourceToBuffer(const GrVertexBuffer* buffer,
-                                 GrVertexLayout vertexLayout);
+    void setVertexSourceToBuffer(GrVertexLayout vertexLayout,
+                                 const GrVertexBuffer* buffer);
 
     /**
      * Sets source of index data for the next indexed draw. Data does not have
@@ -600,10 +637,10 @@
      *                     specified primitive.
      */
     virtual void drawIndexed(PrimitiveType type,
-                             uint32_t startVertex,
-                             uint32_t startIndex,
-                             uint32_t vertexCount,
-                             uint32_t indexCount) = 0;
+                             int startVertex,
+                             int startIndex,
+                             int vertexCount,
+                             int indexCount) = 0;
 
     /**
      * Draws non-indexed geometry using the current state and current vertex
@@ -615,8 +652,8 @@
      * @param vertexCount  one greater than the max index.
      */
     virtual void drawNonIndexed(PrimitiveType type,
-                                uint32_t startVertex,
-                                uint32_t vertexCount)  = 0;
+                                int startVertex,
+                                int vertexCount)  = 0;
 
     ///////////////////////////////////////////////////////////////////////////
 
@@ -631,14 +668,14 @@
     };
 
     ///////////////////////////////////////////////////////////////////////////
-    
+
     class AutoViewMatrixRestore : ::GrNoncopyable {
     public:
         AutoViewMatrixRestore() {
             fDrawTarget = NULL;
         }
 
-        AutoViewMatrixRestore(GrDrawTarget* target) 
+        AutoViewMatrixRestore(GrDrawTarget* target)
             : fDrawTarget(target), fMatrix(fDrawTarget->getViewMatrix()) {
             GrAssert(NULL != target);
         }
@@ -850,10 +887,16 @@
 
     virtual void clipWillChange(const GrClip& clip) = 0;
 
+    virtual void setVertexSourceToArrayHelper(const void* vertexArray,
+                                              int vertexCount) = 0;
+
+    virtual void setIndexSourceToArrayHelper(const void* indexArray,
+                                             int indexCount) = 0;
+
     enum GeometrySrcType {
-        kArray_GeometrySrcType,
-        kReserved_GeometrySrcType,
-        kBuffer_GeometrySrcType
+        kReserved_GeometrySrcType,  // src was set using reserveAndLockGeometry
+        kArray_GeometrySrcType,     // src was set using set*SourceToArray
+        kBuffer_GeometrySrcType     // src was set using set*SourceToBuffer
     };
 
     struct {
@@ -863,25 +906,21 @@
     } fReservedGeometry;
 
     struct GeometrySrc {
-        GeometrySrcType             fVertexSrc;
-        union {
-            const GrVertexBuffer*   fVertexBuffer;
-            const void*             fVertexArray;
-        };
-        GeometrySrcType             fIndexSrc;
-        union {
-            const GrIndexBuffer*    fIndexBuffer;
-            const void*             fIndexArray;
-        };
-        GrVertexLayout              fVertexLayout;
+        GeometrySrcType         fVertexSrc;
+        const GrVertexBuffer*   fVertexBuffer; // valid if src type is buffer
+        GeometrySrcType         fIndexSrc;
+        const GrIndexBuffer*    fIndexBuffer; // valid if src type is buffer
+        GrVertexLayout          fVertexLayout;
     } fGeometrySrc;
 
     GrClip fClip;
 
     DrState fCurrDrawState;
 
-    // not meant for outside usage. Could cause problems if calls between
-    // the save and restore mess with reserved geometry state.
+    // Not meant for external use. Only setVertexSourceToBuffer and
+    // setIndexSourceToBuffer will work since GrDrawTarget subclasses don't
+    // support nested reserveAndLockGeometry (and cpu arrays internally use the
+    // same path).
     class AutoGeometrySrcRestore {
     public:
         AutoGeometrySrcRestore(GrDrawTarget* target) {
diff --git a/gpu/include/GrGLConfig.h b/gpu/include/GrGLConfig.h
index bb10567..c2fdc0d 100644
--- a/gpu/include/GrGLConfig.h
+++ b/gpu/include/GrGLConfig.h
@@ -69,18 +69,15 @@
  *      4. Define GR_GL_PROC_ADDRESS.
  *      5. Optionally define GR_GL_PROC_ADDRESS_HEADER
  *
+ *------------------------------------------------------------------------------
  *
  * The following are optional defines that can be enabled as command line macros
  * defines, in a IDE project, in a GrUserConfig.h file, or in a GL custom setup
  * file (if one is in use). They don't require GR_GL_CUSTOM_SETUP or
  * GR_GL_CUSTOM_SETUP_HEADER to be enabled:
  *
- * GR_GL_NO_CLIENT_SIDE_ARRAYS can be defined to 1 to disable the use of client
- * side vertex and index arrays.
- *
  * GR_GL_LOG_CALLS if 1 GrPrintf every GL call (for debugging purposes) when the
  * global gPrintGL is true (it is initially true).
-
  */
 
 #if GR_GL_CUSTOM_SETUP
@@ -204,10 +201,6 @@
     #define GR_GL_LOG_CALLS 0
 #endif
 
-#if !defined(GR_GL_NO_CLIENT_SIDE_ARRAYS)
-    #define GR_GL_NO_CLIENT_SIDE_ARRAYS 0
-#endif
-
 ////////////////////////////////////////////////////////////////////////////////
 
 #if GR_SCALAR_IS_FIXED
@@ -374,4 +367,3 @@
 #endif
 
 #endif
-
diff --git a/gpu/include/GrGLConfig_chrome.h b/gpu/include/GrGLConfig_chrome.h
index 490a07e..e61a66c 100644
--- a/gpu/include/GrGLConfig_chrome.h
+++ b/gpu/include/GrGLConfig_chrome.h
@@ -18,6 +18,4 @@
 // chrome always assumes BGRA
 #define GR_GL_32BPP_COLOR_FORMAT    GR_BGRA
 
-#define GR_GL_NO_CLIENT_SIDE_ARRAYS 1
-
 #endif
diff --git a/gpu/include/GrGLIndexBuffer.h b/gpu/include/GrGLIndexBuffer.h
index 5177b4b..5755c07 100644
--- a/gpu/include/GrGLIndexBuffer.h
+++ b/gpu/include/GrGLIndexBuffer.h
@@ -27,7 +27,7 @@
 protected:
     GrGLIndexBuffer(GLuint id,
                     GrGpuGL* gl,
-                    uint32_t sizeInBytes,
+                    size_t sizeInBytes,
                     bool dynamic);
 public:
     virtual ~GrGLIndexBuffer();
@@ -37,10 +37,16 @@
     // overrides of GrIndexBuffer
     virtual void abandon();
     virtual void* lock();
+    virtual void* lockPtr() const;
     virtual void unlock();
     virtual bool isLocked() const;
-    virtual bool updateData(const void* src, uint32_t srcSizeInBytes);
+    virtual bool updateData(const void* src, size_t srcSizeInBytes);
+    virtual bool updateSubData(const void* src,  
+                               size_t srcSizeInBytes, 
+                               size_t offset);
 private:
+    void bind() const;
+    
     GrGpuGL*     fGL;
     GLuint       fBufferID;
     void*        fLockPtr;
diff --git a/gpu/include/GrGLVertexBuffer.h b/gpu/include/GrGLVertexBuffer.h
index 6b99f57..30ae734 100644
--- a/gpu/include/GrGLVertexBuffer.h
+++ b/gpu/include/GrGLVertexBuffer.h
@@ -27,7 +27,7 @@
 protected:
     GrGLVertexBuffer(GLuint id,
                      GrGpuGL* gl,
-                     uint32_t sizeInBytes,
+                     size_t sizeInBytes,
                      bool dynamic);
 
 public:
@@ -36,13 +36,18 @@
     // overrides of GrVertexBuffer
     virtual void abandon();
     virtual void* lock();
+    virtual void* lockPtr() const;
     virtual void unlock();
     virtual bool isLocked() const;
-    virtual bool updateData(const void* src, uint32_t srcSizeInBytes);
-
+    virtual bool updateData(const void* src, size_t srcSizeInBytes);
+    virtual bool updateSubData(const void* src,  
+                               size_t srcSizeInBytes, 
+                               size_t offset);
     GLuint bufferID() const;
 
 private:
+    void bind() const;
+    
     GrGpuGL*     fGL;
     GLuint       fBufferID;
     void*        fLockPtr;
diff --git a/gpu/include/GrGeometryBuffer.h b/gpu/include/GrGeometryBuffer.h
new file mode 100644
index 0000000..fc3e358
--- /dev/null
+++ b/gpu/include/GrGeometryBuffer.h
@@ -0,0 +1,116 @@
+/*

+ Copyright 2011 Google Inc.

+ 

+ Licensed under the Apache License, Version 2.0 (the "License");

+ you may not use this file except in compliance with the License.

+ You may obtain a copy of the License at

+ 

+ http://www.apache.org/licenses/LICENSE-2.0

+ 

+ Unless required by applicable law or agreed to in writing, software

+ distributed under the License is distributed on an "AS IS" BASIS,

+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ See the License for the specific language governing permissions and

+ limitations under the License.

+ */

+

+#ifndef GrGeometryBuffer_DEFINED

+#define GrGeometryBuffer_DEFINED

+

+#include "GrRefCnt.h"

+

+/**

+ * Parent class for vertex and index buffers

+ */

+class GrGeometryBuffer : public GrRefCnt {

+public:

+    virtual ~GrGeometryBuffer() {}

+    

+    /**

+     * Retrieves the size of the buffer

+     *

+     * @return the size of the buffer in bytes

+     */

+    size_t size() { return fSizeInBytes; }

+    

+    /**

+     *Retrieves whether the buffer was created with the dynamic flag

+     *

+     * @return true if the buffer was created with the dynamic flag

+     */

+    bool dynamic() const { return fDynamic; }

+    

+    /**

+     * Indicates that GPU context in which this veretx buffer was created is 

+     * destroyed and that Ganesh should not attempt to free the buffer in the

+     * underlying API.

+     */

+    virtual void abandon() = 0;

+    

+    /**

+     * Locks the buffer to be written by the CPU.

+     * 

+     * The previous content of the buffer is invalidated. It is an error

+     * to draw from the buffer while it is locked. It is an error to call lock

+     * on an already locked buffer.

+     * 

+     * @return a pointer to the data or NULL if the lock fails.

+     */

+    virtual void* lock() = 0;

+    

+    /**

+     * Returns the same ptr that lock() returned at time of lock or NULL if the

+     * is not locked.

+     *

+     * @return ptr to locked buffer data or undefined if buffer is not locked.

+     */

+    virtual void* lockPtr() const = 0;

+    

+    /** 

+     * Unlocks the buffer. 

+     * 

+     * The pointer returned by the previous lock call will no longer be valid.

+     */

+    virtual void unlock() = 0;

+    

+    /** 

+     Queries whether the buffer has been locked.

+     

+     @return true if the buffer is locked, false otherwise.

+     */

+    virtual bool isLocked() const = 0;

+    

+    /**

+     * Updates the buffer data. 

+     *  

+     * The size of the buffer will be preserved. The src data will be 

+     * placed at the begining of the buffer and any remaining contents will

+     * be undefined.

+     * 

+     * @return returns true if the update succeeds, false otherwise.

+     */

+    virtual bool updateData(const void* src, size_t srcSizeInBytes) = 0;

+    

+    /**

+     * Updates a portion of the buffer data. 

+     * 

+     * The contents of the buffer outside the update region are preserved.

+     * 

+     * @return returns true if the update succeeds, false otherwise.

+     */

+    virtual bool updateSubData(const void* src, 

+                               size_t srcSizeInBytes, 

+                               size_t offset) = 0;

+protected:

+    GrGeometryBuffer(size_t sizeInBytes, bool dynamic) : 

+        fSizeInBytes(sizeInBytes),

+        fDynamic(dynamic) {}

+

+private:

+    size_t fSizeInBytes;

+    bool     fDynamic;

+    

+    typedef GrRefCnt INHERITED;

+};

+

+#endif

diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h
index 2bbb419..9fb7b9c 100644
--- a/gpu/include/GrGpu.h
+++ b/gpu/include/GrGpu.h
@@ -25,6 +25,8 @@
 #include "GrTexture.h"
 #include "GrMemory.h"
 
+class GrVertexBufferAllocPool;
+class GrIndexBufferAllocPool;
 
 class GrGpu : public GrDrawTarget {
 
@@ -277,20 +279,20 @@
      *
      * @return    the true if NPOT texture/rendertarget can be created.
      */
-    bool npotRenderTargetSupport() const { return fNPOTRenderTargetSupport; } 
+    bool npotRenderTargetSupport() const { return fNPOTRenderTargetSupport; }
 
     int maxTextureDimension() const { return fMaxTextureDimension; }
 
     // GrDrawTarget overrides
     virtual void drawIndexed(PrimitiveType type,
-                             uint32_t startVertex,
-                             uint32_t startIndex,
-                             uint32_t vertexCount,
-                             uint32_t indexCount);
+                             int startVertex,
+                             int startIndex,
+                             int vertexCount,
+                             int indexCount);
 
     virtual void drawNonIndexed(PrimitiveType type,
-                                uint32_t startVertex,
-                                uint32_t vertexCount);
+                                int startVertex,
+                                int vertexCount);
 
     /**
      * Determines if blend is effectively disabled.
@@ -341,7 +343,7 @@
                                         /* rendering a hard clip to the stencil
                                            buffer. Subsequent draws with other
                                            StencilPass values will be clipped
-                                           if kStencilClip_StateBit is set. */
+                                           if kClip_StateBit is set. */
         kGpuCount_StencilPass
     };
 
@@ -384,6 +386,29 @@
     int fMinRenderTargetHeight;
     int fMaxTextureDimension;
 
+    Stats           fStats;
+
+    const GrVertexBuffer*           fCurrPoolVertexBuffer;
+    int                             fCurrPoolStartVertex;
+
+    const GrIndexBuffer*            fCurrPoolIndexBuffer;
+    int                             fCurrPoolStartIndex;
+
+    // GrDrawTarget overrides
+    virtual bool acquireGeometryHelper(GrVertexLayout vertexLayout,
+                                       void**         vertices,
+                                       void**         indices);
+    virtual void releaseGeometryHelper();
+
+    virtual void setVertexSourceToArrayHelper(const void* vertexArray,
+                                              int vertexCount);
+
+    virtual void setIndexSourceToArrayHelper(const void* indexArray,
+                                             int indexCount);
+    // Helpers for setting up geometry state
+    void finalizeReservedVertices();
+    void finalizeReservedIndices();
+
     // overridden by API specific GrGpu-derived class to perform the draw call.
     virtual void drawIndexedHelper(PrimitiveType type,
                                    uint32_t startVertex,
@@ -396,11 +421,12 @@
                                       uint32_t numVertices) = 0;
 
     // called to program the vertex data, indexCount will be 0 if drawing non-
-    // indexed geometry.
-    virtual void setupGeometry(uint32_t startVertex,
-                               uint32_t startIndex,
-                               uint32_t vertexCount,
-                               uint32_t indexCount) = 0;
+    // indexed geometry. The subclass may adjust the startVertex and/or
+    // startIndex since it may have already accounted for these in the setup.
+    virtual void setupGeometry(int* startVertex,
+                               int* startIndex,
+                               int vertexCount,
+                               int indexCount) = 0;
 
 
     // The GrGpu typically records the clients requested state and then flushes
@@ -415,33 +441,21 @@
     // GrGpu subclass removes the clip from the stencil buffer
     virtual void eraseStencilClip() = 0;
 
-    // GrDrawTarget overrides
-    virtual bool acquireGeometryHelper(GrVertexLayout vertexLayout,
-                                       void**         vertices,
-                                       void**         indices);
-    virtual void releaseGeometryHelper();
-
 private:
-    mutable GrIndexBuffer* fQuadIndexBuffer; // mutable so it can be
-                                             // created on-demand
 
-    mutable GrVertexBuffer* fUnitSquareVertexBuffer; // mutable so it can be
-                                                     // created on-demand
+    void prepareVertexPool();
+    void prepareIndexPool();
 
-    static const int MAX_VERTEX_SIZE = GR_CT_MAX(2*sizeof(GrPoint) + sizeof(GrColor),
-                                                 2*sizeof(GrGpuTextVertex));
-    static const int VERTEX_STORAGE = 16 * MAX_VERTEX_SIZE;
-    static const int INDEX_STORAGE = 32 * sizeof(uint16_t);
+    GrVertexBufferAllocPool*    fVertexPool;
 
-protected:
-    GrAutoSMalloc<VERTEX_STORAGE> fVertices;
-    GrAutoSMalloc<INDEX_STORAGE>  fIndices;
+    GrIndexBufferAllocPool*     fIndexPool;
 
-    Stats           fStats;
+    mutable GrIndexBuffer*      fQuadIndexBuffer; // mutable so it can be
+                                                  // created on-demand
 
-private:
-    typedef GrRefCnt INHERITED;
+    mutable GrVertexBuffer*     fUnitSquareVertexBuffer; // mutable so it can be
+                                                         // created on-demand
+    typedef GrDrawTarget INHERITED;
 };
 
 #endif
-
diff --git a/gpu/include/GrInOrderDrawBuffer.h b/gpu/include/GrInOrderDrawBuffer.h
index 805861a..463ea2d 100644
--- a/gpu/include/GrInOrderDrawBuffer.h
+++ b/gpu/include/GrInOrderDrawBuffer.h
@@ -24,30 +24,43 @@
 #include "GrClip.h"
 
 class GrVertexBufferAllocPool;
+class GrIndexBufferAllocPool;
 
-// TODO: don't save clip per draw
+/**
+ * GrInOrderDrawBuffer is an implementation of GrDrawTarget that queues up
+ * draws for eventual playback into a GrGpu. In theory one draw buffer could
+ * playback into another. When index or vertex buffers are used as geometry
+ * sources it is the callers the draw buffer only holds references to the
+ * buffers. It is the callers responsibility to ensure that the data is still
+ * valid when the draw buffer is played back into a GrGpu. Similarly, it is the
+ * caller's responsibility to ensure that all referenced textures, buffers,
+ * and rendertargets are associated in the GrGpu object that the buffer is
+ * played back into. The buffer requires VB and IB pools to store geometry.
+ */
+
 class GrInOrderDrawBuffer : public GrDrawTarget {
 public:
 
-    GrInOrderDrawBuffer(GrVertexBufferAllocPool* pool = NULL);
+    GrInOrderDrawBuffer(GrVertexBufferAllocPool* vertexPool,
+                        GrIndexBufferAllocPool* indexPool);
 
     virtual ~GrInOrderDrawBuffer();
 
     void initializeDrawStateAndClip(const GrDrawTarget& target);
 
-    virtual void drawIndexed(PrimitiveType type,
-                             uint32_t startVertex,
-                             uint32_t startIndex,
-                             uint32_t vertexCount,
-                             uint32_t indexCount);
+    virtual void drawIndexed(PrimitiveType primitiveType,
+                             int startVertex,
+                             int startIndex,
+                             int vertexCount,
+                             int indexCount);
 
-    virtual void drawNonIndexed(PrimitiveType type,
-                                uint32_t startVertex,
-                                uint32_t vertexCount);
+    virtual void drawNonIndexed(PrimitiveType primitiveType,
+                                int startVertex,
+                                int vertexCount);
 
     virtual bool geometryHints(GrVertexLayout vertexLayout,
-                               int32_t*       vertexCount,
-                               int32_t*       indexCount) const;
+                               int* vertexCount,
+                               int* indexCount) const;
 
     void reset();
 
@@ -56,24 +69,16 @@
 private:
 
     struct Draw {
-        PrimitiveType   fType;
-        uint32_t        fStartVertex;
-        uint32_t        fStartIndex;
-        uint32_t        fVertexCount;
-        uint32_t        fIndexCount;
-        bool            fStateChange;
-        GrVertexLayout  fVertexLayout;
-        bool            fUseVertexBuffer;
-        bool            fClipChanged;
-        union {
-            const GrVertexBuffer*   fVertexBuffer;
-            const void*             fVertexArray;
-        };
-        bool            fUseIndexBuffer;
-        union {
-            const GrIndexBuffer*    fIndexBuffer;
-            const void*             fIndexArray;
-        };
+        PrimitiveType           fPrimitiveType;
+        int                     fStartVertex;
+        int                     fStartIndex;
+        int                     fVertexCount;
+        int                     fIndexCount;
+        bool                    fStateChanged;
+        bool                    fClipChanged;
+        GrVertexLayout          fVertexLayout;
+        const GrVertexBuffer*   fVertexBuffer;
+        const GrIndexBuffer*    fIndexBuffer;
     };
 
     virtual bool acquireGeometryHelper(GrVertexLayout vertexLayout,
@@ -82,33 +87,36 @@
     virtual void releaseGeometryHelper();
     virtual void clipWillChange(const GrClip& clip);
 
+    virtual void setVertexSourceToArrayHelper(const void* vertexArray,
+                                              int vertexCount);
+
+    virtual void setIndexSourceToArrayHelper(const void* indexArray,
+                                             int indexCount);
+
 
     bool grabState();
     bool grabClip();
 
     GrTAllocator<Draw>              fDraws;
-    // HACK: We hold refs on textures in saved state but not RTs, VBs, and IBs.
-    // a) RTs aren't ref counted (yet)
-    // b) we are only using this class for text which doesn't use VBs or IBs
-    // This should be fixed by either refcounting them all or having some
-    // notification occur if a cache is purging an object we have a ptr to.
+    // HACK: We currently do not hold refs on RTs in the saved draw states.
+    // The reason is that in the GL implementation when a GrTexture is destroyed
+    // that has an associated RT the RT is destroyed regardless of its ref count.
+    // We need a third object that holds the shared GL ids and persists until
+    // both reach ref count 0. (skia issue 122)
     GrTAllocator<SavedDrawState>    fStates;
 
     GrTAllocator<GrClip>            fClips;
     bool                            fClipChanged;
 
-    // vertices are either queued in cpu arrays or some vertex buffer pool
-    // that knows about a specific GrGpu object.
-    GrAllocPool                     fCPUVertices;
-    GrVertexBufferAllocPool*        fBufferVertices;
-    GrAllocPool                     fIndices;
-    void*                           fCurrReservedVertices;
-    void*                       	fCurrReservedIndices;
-    // valid if we're queueing vertices in fBufferVertices
-    GrVertexBuffer*                 fCurrVertexBuffer;
-    uint32_t                        fCurrStartVertex;
+    GrVertexBufferAllocPool&        fVertexPool;
+    const GrVertexBuffer*           fCurrPoolVertexBuffer;
+    int                             fCurrPoolStartVertex;
 
-    // caller may conservatively over allocate vertices / indices.
+    GrIndexBufferAllocPool&         fIndexPool;
+    const GrIndexBuffer*            fCurrPoolIndexBuffer;
+    int                             fCurrPoolStartIndex;
+
+    // caller may conservatively over reserve vertices / indices.
     // we release unused space back to allocator if possible
     size_t                          fReservedVertexBytes;
     size_t                          fReservedIndexBytes;
diff --git a/gpu/include/GrIndexBuffer.h b/gpu/include/GrIndexBuffer.h
index 0f4c4d6..85ff749 100644
--- a/gpu/include/GrIndexBuffer.h
+++ b/gpu/include/GrIndexBuffer.h
@@ -18,75 +18,14 @@
 #ifndef GrIndexBuffer_DEFINED
 #define GrIndexBuffer_DEFINED
 
-#include "GrRefCnt.h"
+#include "GrGeometryBuffer.h"
 
-class GrIndexBuffer : public GrRefCnt {
+class GrIndexBuffer : public GrGeometryBuffer {
 protected:
-    GrIndexBuffer(uint32_t sizeInBytes, bool dynamic) : 
-                  fSizeInBytes(sizeInBytes),
-                  fDynamic(dynamic) {}
-public:
-    virtual ~GrIndexBuffer() {}
-    
-    /**
-     Retrieves the size of the index buffer
-
-     @return the size of the index buffer in bytes
-     */
-    uint32_t size() const { return fSizeInBytes; }
-   
-    /**
-     Retrieves whether the index buffer was created with the dynamic flag
-
-     @return true if the index buffer was created with the dynamic flag
-     */
-    bool dynamic() const { return fDynamic; }
-
-    /**
-     Indicates that GPU context in which this veretx buffer was created is 
-     destroyed and that Ganesh should not attempt to free the texture with the
-     underlying API.
-     */
-    virtual void abandon() = 0;
-
-    /**
-     Locks the index buffer to be written by the CPU.
-     
-     The previous content of the index buffer is invalidated. It is an error to
-     draw whil the buffer is locked.  It is an error to call lock on an already
-     locked index buffer.
-     
-     @return a pointer to the index data or NULL if the lock fails.
-     */
-    virtual void* lock() = 0;
-
-    /** 
-     Unlocks the index buffer. 
-     
-     The pointer returned by the previous lock call will no longer be valid.
-     */
-    virtual void unlock() = 0;
-
-    /** 
-     Queries whether the index buffer has been locked.
-     
-     @return true if the index buffer is locked, false otherwise.
-     */
-    virtual bool isLocked() const = 0;
-
-    /**
-     Updates the index buffer data. 
-     
-     The size of the index buffer will be preserved. However, only the updated 
-     region will have defined contents.
-
-     @return returns true if the update succeeds, false otherwise.
-     */
-    virtual bool updateData(const void* src, uint32_t srcSizeInBytes) = 0;
-
+    GrIndexBuffer(size_t sizeInBytes, bool dynamic) :
+        INHERITED(sizeInBytes, dynamic) {}
 private:
-    uint32_t fSizeInBytes;
-    bool     fDynamic;
+    typedef GrGeometryBuffer INHERITED;
 };
 
 #endif
diff --git a/gpu/include/GrMemory.h b/gpu/include/GrMemory.h
index 673d0ab..be8b1d7 100644
--- a/gpu/include/GrMemory.h
+++ b/gpu/include/GrMemory.h
@@ -22,7 +22,10 @@
 
 class GrAutoMalloc : GrNoncopyable {
 public:
-    GrAutoMalloc(size_t bytes) : fPtr(GrMalloc(bytes)) {}
+    GrAutoMalloc() : fPtr(NULL), fAllocatedBytes(0){
+    }
+
+    GrAutoMalloc(size_t bytes) : fPtr(GrMalloc(bytes)), fAllocatedBytes(bytes) {}
     ~GrAutoMalloc() { GrFree(fPtr); }
 
     /**
@@ -31,6 +34,8 @@
      */
     void* get() const { return fPtr; }
 
+    size_t size() const { return fAllocatedBytes; }
+
     /**
      *  transfer ownership of the memory to the caller. It must be freed with
      *  a call to GrFree()
@@ -38,19 +43,44 @@
     void* detach() {
         void* ptr = fPtr;
         fPtr = NULL;    // we no longer own the block
+        fAllocatedBytes = 0;
         return ptr;
     }
-    
+
+    /**
+     *  Reallocates to a new size. May or may not call malloc. The contents
+     *  are not preserved. If growOnly is true it will never reduce the
+     *  allocated size.
+     */
+    void* realloc(size_t newSize, bool growOnly = false) {
+        bool alloc;
+        if (growOnly) {
+            alloc = newSize > fAllocatedBytes;
+        } else {
+            alloc = newSize != fAllocatedBytes;
+        }
+        if (alloc) {
+            GrFree(fPtr);
+            fPtr = newSize ? GrMalloc(newSize) : NULL;
+            fAllocatedBytes = newSize;
+        }
+        GrAssert(fAllocatedBytes >= newSize);
+        GR_DEBUGCODE(memset(fPtr, 0xEF, fAllocatedBytes));
+        return fPtr;
+    }
+
     /**
      *  free the block now. get() will now return NULL
      */
     void free() {
         GrFree(fPtr);
         fPtr = NULL;
+        fAllocatedBytes = 0;
     }
 
 private:
     void* fPtr;
+    size_t fAllocatedBytes;
 };
 
 /**
@@ -86,10 +116,10 @@
      *  detached.
      */
     void* get() const { return fPtr; }
-    
+
     /**
-     *  Reallocates to a new size. May or may not call malloc. The contents 
-     *  are not preserved. If growOnly is true it will never reduce the 
+     *  Reallocates to a new size. May or may not call malloc. The contents
+     *  are not preserved. If growOnly is true it will never reduce the
      *  allocated size.
      */
     void* realloc(size_t newSize, bool growOnly = false) {
@@ -101,7 +131,7 @@
                 GrFree(fPtr);
                 fPtr = fStorage;
                 fAllocatedBytes = SIZE;
-            }            
+            }
         } else if ((newSize > fAllocatedBytes) ||
                    (!growOnly && newSize < (fAllocatedBytes >> 1))) {
             if (NULL != fPtr && fPtr != (void*)fStorage) {
@@ -115,7 +145,7 @@
         GR_DEBUGCODE(memset(fPtr, 0xEF, fAllocatedBytes));
         return fPtr;
     }
-   
+
     /**
      *  free the block now. get() will now return NULL
      */
@@ -126,7 +156,7 @@
         fAllocatedBytes = 0;
         fPtr = NULL;
     }
-    
+
 private:
     void*    fPtr;
     uint32_t fAllocatedBytes;
diff --git a/gpu/include/GrTArray.h b/gpu/include/GrTArray.h
index f0d9494..c31c820 100644
--- a/gpu/include/GrTArray.h
+++ b/gpu/include/GrTArray.h
@@ -21,8 +21,6 @@
 #include <new>
 #include "GrTypes.h"
 
-// TODO: convert from uint32_t to int.
-
 // DATA_TYPE indicates that T has a trivial cons, destructor
 // and can be shallow-copied
 template <typename T, bool DATA_TYPE = false> class GrTArray {
@@ -35,15 +33,18 @@
         fPreAllocMemArray = NULL;
     }
 
-    GrTArray(uint32_t reserveCount) {
+    explicit GrTArray(int reserveCount) {
+        GrAssert(reserveCount >= 0);
         fCount = 0;
-        fReserveCount = GrMax(reserveCount, (uint32_t)MIN_ALLOC_COUNT);
+        fReserveCount = reserveCount > MIN_ALLOC_COUNT ? reserveCount :
+                                                         MIN_ALLOC_COUNT;
         fAllocCount = fReserveCount;
         fMemArray = GrMalloc(sizeof(T) * fReserveCount);
         fPreAllocMemArray = NULL;
     }
 
-    GrTArray(void* preAllocStorage, uint32_t preAllocCount) {
+    GrTArray(void* preAllocStorage, int preAllocCount) {
+        GrAssert(preAllocCount >= 0);
         // we allow NULL,0 args and revert to the default cons. behavior
         // this makes it possible for a owner-object to use same constructor
         // to get either prealloc or nonprealloc behavior based using same line
@@ -57,7 +58,7 @@
         fPreAllocMemArray   = preAllocStorage;
     }
 
-    GrTArray(const GrTArray& array) {
+    explicit GrTArray(const GrTArray& array) {
         fCount              = array.count();
         fReserveCount       = MIN_ALLOC_COUNT;
         fAllocCount         = GrMax(fReserveCount, fCount);
@@ -66,13 +67,14 @@
         if (DATA_TYPE) {
             memcpy(fMemArray, array.fMemArray, sizeof(T) * fCount);
         } else {
-            for (uint32_t i = 0; i < fCount; ++i) {
+            for (int i = 0; i < fCount; ++i) {
                 new (fItemArray + i) T(array[i]);
             }
         }
     }
 
-    GrTArray(const T* array, uint32_t count) {
+    GrTArray(const T* array, int count) {
+        GrAssert(count >= 0);
         fCount              = count;
         fReserveCount       = MIN_ALLOC_COUNT;
         fAllocCount         = GrMax(fReserveCount, fCount);
@@ -81,14 +83,16 @@
         if (DATA_TYPE) {
             memcpy(fMemArray, array, sizeof(T) * fCount);
         } else {
-            for (uint32_t i = 0; i < fCount; ++i) {
+            for (int i = 0; i < fCount; ++i) {
                 new (fItemArray + i) T(array[i]);
             }
         }
     }
 
     GrTArray(const GrTArray& array,
-             void* preAllocStorage, uint32_t preAllocCount) {
+             void* preAllocStorage, int preAllocCount) {
+
+        GrAssert(preAllocCount >= 0);
 
         // for same reason as non-copying cons we allow NULL, 0 for prealloc
         GrAssert((NULL == preAllocStorage) == !preAllocCount);
@@ -109,14 +113,17 @@
         if (DATA_TYPE) {
             memcpy(fMemArray, array.fMemArray, sizeof(T) * fCount);
         } else {
-            for (uint32_t i = 0; i < fCount; ++i) {
+            for (int i = 0; i < fCount; ++i) {
                 new (fItemArray + i) T(array[i]);
             }
         }
     }
 
-    GrTArray(const T* array, uint32_t count,
-             void* preAllocStorage, uint32_t preAllocCount) {
+    GrTArray(const T* array, int count,
+             void* preAllocStorage, int preAllocCount) {
+
+        GrAssert(count >= 0);
+        GrAssert(preAllocCount >= 0);
 
         // for same reason as non-copying cons we allow NULL, 0 for prealloc
         GrAssert((NULL == preAllocStorage) == !preAllocCount);
@@ -137,14 +144,14 @@
         if (DATA_TYPE) {
             memcpy(fMemArray, array, sizeof(T) * fCount);
         } else {
-            for (uint32_t i = 0; i < fCount; ++i) {
+            for (int i = 0; i < fCount; ++i) {
                 new (fItemArray + i) T(array[i]);
             }
         }
     }
 
     GrTArray& operator =(const GrTArray& array) {
-        for (uint32_t i = 0; i < fCount; ++i) {
+        for (int i = 0; i < fCount; ++i) {
             fItemArray[i].~T();
         }
         fCount = 0;
@@ -153,7 +160,7 @@
         if (DATA_TYPE) {
             memcpy(fMemArray, array.fMemArray, sizeof(T) * fCount);
         } else {
-            for (uint32_t i = 0; i < fCount; ++i) {
+            for (int i = 0; i < fCount; ++i) {
                 new (fItemArray + i) T(array[i]);
             }
         }
@@ -161,7 +168,7 @@
     }
 
     ~GrTArray() {
-        for (uint32_t i = 0; i < fCount; ++i) {
+        for (int i = 0; i < fCount; ++i) {
             fItemArray[i].~T();
         }
         if (fMemArray != fPreAllocMemArray) {
@@ -169,7 +176,7 @@
         }
     }
 
-    uint32_t count() const { return fCount; }
+    int count() const { return fCount; }
 
     bool empty() const { return !fCount; }
 
@@ -180,32 +187,36 @@
         return fItemArray[fCount-1];
     }
 
-    void push_back_n(uint32_t n) {
+    void push_back_n(int n) {
+        GrAssert(n >= 0);
         checkRealloc(n);
-        for (uint32_t i = 0; i < n; ++i) {
+        for (int i = 0; i < n; ++i) {
             new (fItemArray + fCount + i) T;
         }
         fCount += n;
     }
 
     void pop_back() {
-        GrAssert(0 != fCount);
+        GrAssert(fCount > 0);
         --fCount;
         fItemArray[fCount].~T();
         checkRealloc(0);
     }
 
-    void pop_back_n(uint32_t n) {
+    void pop_back_n(int n) {
+        GrAssert(n >= 0);
         GrAssert(fCount >= n);
         fCount -= n;
-        for (uint32_t i = 0; i < n; ++i) {
+        for (int i = 0; i < n; ++i) {
             fItemArray[i].~T();
         }
         checkRealloc(0);
     }
 
     // pushes or pops from the back to resize
-    void resize_back(uint32_t newCount) {
+    void resize_back(int newCount) {
+        GrAssert(newCount >= 0);
+
         if (newCount > fCount) {
             push_back_n(newCount - fCount);
         } else if (newCount < fCount) {
@@ -213,42 +224,50 @@
         }
     }
 
-    T& operator[] (uint32_t i) {
+    T& operator[] (int i) {
         GrAssert(i < fCount);
+        GrAssert(i >= 0);
         return fItemArray[i];
     }
 
-    const T& operator[] (uint32_t i) const {
+    const T& operator[] (int i) const {
         GrAssert(i < fCount);
+        GrAssert(i >= 0);
         return fItemArray[i];
     }
 
-    T& front() { GrAssert(fCount); return fItemArray[0];}
+    T& front() { GrAssert(fCount > 0); return fItemArray[0];}
 
-    const T& front() const { GrAssert(fCount); return fItemArray[0];}
+    const T& front() const { GrAssert(fCount > 0); return fItemArray[0];}
 
     T& back() { GrAssert(fCount); return fItemArray[fCount - 1];}
 
-    const T& back() const { GrAssert(fCount); return fItemArray[fCount - 1];}
+    const T& back() const { GrAssert(fCount > 0); return fItemArray[fCount - 1];}
 
-    T& fromBack(uint32_t i) {
+    T& fromBack(int i) {
+        GrAssert(i >= 0);
         GrAssert(i < fCount);
         return fItemArray[fCount - i - 1];
     }
 
-    const T& fromBack(uint32_t i) const {
+    const T& fromBack(int i) const {
+        GrAssert(i >= 0);
         GrAssert(i < fCount);
         return fItemArray[fCount - i - 1];
     }
 
 private:
-    static const uint32_t MIN_ALLOC_COUNT = 8;
 
-    inline void checkRealloc(int32_t delta) {
-        GrAssert(-delta <= (int32_t)fCount);
+    static const int MIN_ALLOC_COUNT = 8;
 
-        uint32_t newCount = fCount + delta;
-        uint32_t fNewAllocCount = fAllocCount;
+    inline void checkRealloc(int delta) {
+        GrAssert(fCount >= 0);
+        GrAssert(fAllocCount >= 0);
+
+        GrAssert(-delta <= fCount);
+
+        int newCount = fCount + delta;
+        int fNewAllocCount = fAllocCount;
 
         if (newCount > fAllocCount) {
             fNewAllocCount = GrMax(newCount + ((newCount + 1) >> 1),
@@ -271,7 +290,7 @@
             if (DATA_TYPE) {
                 memcpy(fNewMemArray, fMemArray, fCount * sizeof(T));
             } else {
-                for (uint32_t i = 0; i < fCount; ++i) {
+                for (int i = 0; i < fCount; ++i) {
                     new (fNewMemArray + sizeof(T) * i) T(fItemArray[i]);
                     fItemArray[i].~T();
                 }
@@ -284,9 +303,9 @@
         }
     }
 
-    uint32_t fReserveCount;
-    uint32_t fCount;
-    uint32_t fAllocCount;
+    int fReserveCount;
+    int fCount;
+    int fAllocCount;
     void*    fPreAllocMemArray;
     union {
         T*       fItemArray;
diff --git a/gpu/include/GrTexture.h b/gpu/include/GrTexture.h
index 71a58e6..4776539 100644
--- a/gpu/include/GrTexture.h
+++ b/gpu/include/GrTexture.h
@@ -25,10 +25,9 @@
 /**
  * GrRenderTarget represents a 2D buffer of pixels that can be rendered to.
  * A context's render target is set by setRenderTarget(). Render targets are
- * created by a createTexture with the kRenderTarget_TextureFlag flag. 
- * Additionally, the rendering destination set in the underlying 3D API at the
- * time of GrContext's creation can be retrieved by calling 
- * currentRenderTarget() after creation before any calles to setRenderTarget().
+ * created by a createTexture with the kRenderTarget_TextureFlag flag.
+ * Additionally, GrContext provides methods for creating GrRenderTargets
+ * that wrap externally created render targets.
  */
 class GrRenderTarget : public GrRefCnt {
 public:
@@ -40,7 +39,7 @@
      * @return the height of the rendertarget
      */
     virtual uint32_t height() const = 0;
-    
+
     /**
      * @return the texture associated with the rendertarget, may be NULL.
      */
@@ -70,10 +69,10 @@
               uint32_t contentHeight,
               uint32_t allocWidth,
               uint32_t allocHeight,
-              PixelConfig config) : 
-                fAllocWidth(allocWidth), 
+              PixelConfig config) :
+                fAllocWidth(allocWidth),
                 fAllocHeight(allocHeight),
-                fContentWidth(contentWidth), 
+                fContentWidth(contentWidth),
                 fContentHeight(contentHeight),
                 fConfig(config) {
                     // only make sense if alloc size is pow2
@@ -82,18 +81,18 @@
                 }
 public:
     virtual ~GrTexture();
-    
+
     /**
      * Retrieves the width of the content area of the texture. Reflects the
      * width passed to GrGpu::createTexture().
-     * 
+     *
      * @return the width in texels
      */
     uint32_t contentWidth() const { return fContentWidth; }
     /**
      * Retrieves the height of the content area of the texture. Reflects the
      * height passed to GrGpu::createTexture().
-     * 
+     *
      * @return the height in texels
      */
     uint32_t contentHeight() const { return fContentHeight; }
@@ -120,7 +119,7 @@
     GrFixed normalizeFixedY(GrFixed y) const { GrAssert(GrIsPow2(fAllocHeight));
                                                return y >> fShiftFixedY; }
 
-    /** 
+    /**
      * Retrieves the pixel config specified when the texture was created.
      */
     PixelConfig config() const { return fConfig; }
@@ -149,7 +148,7 @@
                                    const void* srcData) = 0;
     /**
      * Indicates that GPU context in which this texture was created is destroyed
-     * and that Ganesh should not attempt to free the texture with the 
+     * and that Ganesh should not attempt to free the texture with the
      * underlying API.
      */
     virtual void abandon() = 0;
@@ -157,7 +156,7 @@
     /**
      * Queries whether the texture was created as a render target.
      *
-     * Use asRenderTarget() to use the texture as a render target if this 
+     * Use asRenderTarget() to use the texture as a render target if this
      * returns true.
      *
      * @return true if the texture was created as a render target.
@@ -194,8 +193,8 @@
 #else
     void validate() const {}
 #endif
-    
-private:    
+
+private:
     uint32_t fAllocWidth;
     uint32_t fAllocHeight;
     uint32_t fContentWidth;
diff --git a/gpu/include/GrTypes.h b/gpu/include/GrTypes.h
index a799c2e..9553678 100644
--- a/gpu/include/GrTypes.h
+++ b/gpu/include/GrTypes.h
@@ -45,28 +45,40 @@
 /**
  *  divide, rounding up
  */
-inline uint32_t GrUIDivRoundUp(uint32_t x, uint32_t y) {
+static inline uint32_t GrUIDivRoundUp(uint32_t x, uint32_t y) {
+    return (x + (y-1)) / y;
+}
+static inline size_t GrSizeDivRoundUp(size_t x, uint32_t y) {
     return (x + (y-1)) / y;
 }
 
 /**
  *  align up
  */
-inline uint32_t GrUIAlignUp(uint32_t x, uint32_t alignment) {
+static inline uint32_t GrUIAlignUp(uint32_t x, uint32_t alignment) {
     return GrUIDivRoundUp(x, alignment) * alignment;
 }
+static inline uint32_t GrSizeAlignUp(size_t x, uint32_t alignment) {
+    return GrSizeDivRoundUp(x, alignment) * alignment;
+}
 
 /**
  * amount of pad needed to align up
  */
-inline uint32_t GrUIAlignUpPad(uint32_t x, uint32_t alignment) {
+static inline uint32_t GrUIAlignUpPad(uint32_t x, uint32_t alignment) {
+    return (alignment - x % alignment) % alignment;
+}
+static inline size_t GrSizeAlignUpPad(size_t x, uint32_t alignment) {
     return (alignment - x % alignment) % alignment;
 }
 
 /**
  *  align down
  */
-inline uint32_t GrUIAlignDown(uint32_t x, uint32_t alignment) {
+static inline uint32_t GrUIAlignDown(uint32_t x, uint32_t alignment) {
+    return (x / alignment) * alignment;
+}
+static inline uint32_t GrSizeAlignDown(size_t x, uint32_t alignment) {
     return (x / alignment) * alignment;
 }
 
diff --git a/gpu/include/GrUserConfig.h b/gpu/include/GrUserConfig.h
index 155dc8c..4d44172 100644
--- a/gpu/include/GrUserConfig.h
+++ b/gpu/include/GrUserConfig.h
@@ -65,6 +65,13 @@
  */
 //#define GR_AGGRESSIVE_SHADER_OPTS 1
 
+/*
+ * This gives a threshold in bytes of when to lock a GrGeometryBuffer vs using
+ * updateData or updateSubData. (Note the depending on the underlying 3D API
+ * the update functions may always be implemented using a lock)
+ */
+//#define GR_GEOM_BUFFER_LOCK_THRESHOLD (1<<15)
+
 ///////////////////////////////////////////////////////////////////////////////
 /*
  *  temporary flags (may go away soon)
diff --git a/gpu/include/GrVertexBuffer.h b/gpu/include/GrVertexBuffer.h
index 5e83de9..3792c15 100644
--- a/gpu/include/GrVertexBuffer.h
+++ b/gpu/include/GrVertexBuffer.h
@@ -18,75 +18,14 @@
 #ifndef GrVertexBuffer_DEFINED
 #define GrVertexBuffer_DEFINED
 
-#include "GrRefCnt.h"
+#include "GrGeometryBuffer.h"
 
-class GrVertexBuffer : public GrRefCnt {
+class GrVertexBuffer : public GrGeometryBuffer {
 protected:
-    GrVertexBuffer(uint32_t sizeInBytes, bool dynamic) : 
-             fSizeInBytes(sizeInBytes),
-             fDynamic(dynamic) {}
-public:
-    virtual ~GrVertexBuffer() {}
-    
-    /**
-     Retrieves the size of the vertex buffer
-
-     @return the size of the vertex buffer in bytes
-     */
-    uint32_t size() { return fSizeInBytes; }
-
-    /**
-     Retrieves whether the vertex buffer was created with the dynamic flag
-
-     @return true if the vertex buffer was created with the dynamic flag
-     */
-    bool dynamic() const { return fDynamic; }
-
-    /**
-     Indicates that GPU context in which this veretx buffer was created is 
-     destroyed and that Ganesh should not attempt to free the texture with the
-     underlying API.
-     */
-    virtual void abandon() = 0;
-
-    /**
-     Locks the vertex buffer to be written by the CPU.
-     
-     The previous content of the vertex buffer is invalidated. It is an error to
-     draw whil the buffer is locked.  It is an error to call lock on an already
-     locked vertex buffer.
-     
-     @return a pointer to the vertex data or NULL if the lock fails.
-     */
-    virtual void* lock() = 0;
-
-    /** 
-     Unlocks the vertex buffer. 
-     
-     The pointer returned by the previous lock call will no longer be valid.
-     */
-    virtual void unlock() = 0;
-
-    /** 
-     Queries whether the vertex buffer has been locked.
-     
-     @return true if the vertex buffer is locked, false otherwise.
-     */
-    virtual bool isLocked() const = 0;
-
-    /**
-     Updates the vertex buffer data. 
-     
-     The size of the vertex buffer will be preserved. However, only the updated
-     region will have defined contents.
-
-     @return returns true if the update succeeds, false otherwise.
-     */
-    virtual bool updateData(const void* src, uint32_t srcSizeInBytes) = 0;
-
+    GrVertexBuffer(size_t sizeInBytes, bool dynamic) : 
+        INHERITED(sizeInBytes, dynamic) {}
 private:
-    uint32_t fSizeInBytes;
-    bool     fDynamic;
+    typedef GrGeometryBuffer INHERITED;
 };
 
 #endif
diff --git a/gpu/include/GrVertexBufferAllocPool.h b/gpu/include/GrVertexBufferAllocPool.h
deleted file mode 100644
index 6a781aa..0000000
--- a/gpu/include/GrVertexBufferAllocPool.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
-    Copyright 2010 Google Inc.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
- */
-
-
-#ifndef GrVertexBufferAllocPool_DEFINED
-#define GrVertexBufferAllocPool_DEFINED
-
-#include "GrNoncopyable.h"
-#include "GrTDArray.h"
-#include "GrTArray.h"
-
-class GrVertexBuffer;
-class GrGpu;
-
-/**
- * A pool of vertices in vertex buffers tied to a GrGpu.
- *
- * The pool has an alloc() function that returns a pointer into a locked
- * vertex buffer. A client can release() if it has over-allocated.
- *
- * At creation time a minimum VB size can be specified. Additionally,
- * a number of vertex buffers to preallocate can be specified. These will
- * be allocated at the min size and kept until the pool is destroyed.
- */
-class GrVertexBufferAllocPool : GrNoncopyable {
-public:
-    /**
-     * Constructor
-     *
-     * @param gpu               The GrGpu used to create the vertex buffers.
-     * @param bufferSize        The size of created VBs (unless an alloc request
-     *                          exceeds this size in which case a larger VB is
-     *                          created). This value is clamped to some
-     *                          reasonable minimum.
-     * @param preallocBufferCnt The pool will allocate this number of VBs at
-     *                          bufferSize and keep them until it is destroyed.
-     */
-     GrVertexBufferAllocPool(GrGpu* gpu,
-                             size_t   bufferSize = 0,
-                             int preallocBufferCnt = 0);
-    ~GrVertexBufferAllocPool();
-
-    /**
-     * Ensures all VBs are unlocked. Call before using to draw.
-     */
-    void unlock();
-
-    /**
-     *  Frees all vertex data that has been allocated with alloc().
-     */
-    void reset();
-
-    /**
-     * Returns a block of memory bytes size big. The vertex buffer
-     * containing the memory is returned in buffer.
-     *
-     * @param layout       specifies type of vertices to allocate space for
-     * @param vertexCount  number of vertices to allocate space for
-     * @param buffer       returns the vertex buffer that will hold the
-     *                     vertices.
-     * @param startVertex  returns the offset into buffer of the first vertex.
-     *                     In units of the size of a vertex using layout param.
-     * @return pointer to first vertex.
-     */
-    void* alloc(GrVertexLayout layout,
-                uint32_t vertexCount,
-                GrVertexBuffer** buffer,
-                uint32_t* startVertex);
-
-    /**
-     * Gets the number of vertices that can be allocated without changing VBs.
-     * This means either the last VB returned by alloc() if the last alloc did
-     * not exhaust it. If that VB was exhausted by the last alloc or alloc hasn't
-     * been called since reset() then it will be the number of vertices that
-     * would fit in an available preallocated VB. If no preallocated VB
-     * is available then it returns 0 since the next alloc would force a new
-     * VB to be created.
-     */
-    int currentBufferVertices(GrVertexLayout layout) const;
-
-    /**
-     * Gets the number of preallocated buffers that are yet to be used.
-     */
-    int preallocatedBuffersRemaining() const;
-
-    /**
-     * Gets the number of vertices that can fit in a  preallocated vertex buffer.
-     * Zero if no preallocated buffers.
-     */
-    int preallocatedBufferVertices(GrVertexLayout layout) const;
-
-    /**
-     * gets the number of preallocated vertex buffers
-     */
-    int preallocatedBufferCount() const;
-
-
-    /**
-     * Releases the most recently allocated bytes back to the pool.
-     */
-    void release(size_t bytes);
-
-    /**
-     * Gets the GrGpu that this pool is associated with.
-     */
-    GrGpu* getGpu() { return fGpu; }
-
-
-private:
-    struct BufferBlock {
-        size_t              fBytesFree;
-        GrVertexBuffer*     fVertexBuffer;
-    };
-
-    bool createBlock(size_t size);
-    void destroyBlock();
-
-    GrTArray<BufferBlock>       fBlocks;
-    GrTDArray<GrVertexBuffer*>  fPreallocBuffers;
-    int                         fPreallocBuffersInUse;
-    int                         fFirstPreallocBuffer;
-
-    size_t              fMinBlockSize;
-    GrGpu*              fGpu;
-    void*               fBufferPtr;
-};
-
-#endif
diff --git a/gpu/src/GrBufferAllocPool.cpp b/gpu/src/GrBufferAllocPool.cpp
new file mode 100644
index 0000000..35f0c5e
--- /dev/null
+++ b/gpu/src/GrBufferAllocPool.cpp
@@ -0,0 +1,430 @@
+/*
+    Copyright 2010 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#include "GrBufferAllocPool.h"
+#include "GrTypes.h"
+#include "GrVertexBuffer.h"
+#include "GrIndexBuffer.h"
+#include "GrGpu.h"
+
+#if GR_DEBUG
+    #define VALIDATE validate
+#else
+    #define VALIDATE()
+#endif
+
+#define GrBufferAllocPool_MIN_BLOCK_SIZE ((size_t)1 << 12)
+
+GrBufferAllocPool::GrBufferAllocPool(GrGpu* gpu,
+                                     BufferType bufferType,
+                                     bool frequentResetHint,
+                                     size_t blockSize,
+                                     int preallocBufferCnt) :
+        fBlocks(GrMax(8, 2*preallocBufferCnt)) {
+    GrAssert(NULL != gpu);
+    fGpu = gpu;
+    fBufferType = bufferType;
+    fFrequentResetHint = frequentResetHint;
+    fGpu->ref();
+    fBufferPtr = NULL;
+    fMinBlockSize = GrMax(GrBufferAllocPool_MIN_BLOCK_SIZE, blockSize);
+
+    fPreallocBuffersInUse = 0;
+    fFirstPreallocBuffer = 0;
+    for (int i = 0; i < preallocBufferCnt; ++i) {
+        GrGeometryBuffer* buffer = this->createBuffer(fMinBlockSize);
+        if (NULL != buffer) {
+            *fPreallocBuffers.append() = buffer;
+            buffer->ref();
+        }
+    }
+}
+
+GrBufferAllocPool::~GrBufferAllocPool() {
+    VALIDATE();
+    if (fBlocks.count()) {
+        GrGeometryBuffer* buffer = fBlocks.back().fBuffer;
+        if (buffer->isLocked()) {
+            buffer->unlock();
+        }
+    }
+    fPreallocBuffers.unrefAll();
+    while (!fBlocks.empty()) {
+        destroyBlock();
+    }
+    fGpu->unref();
+}
+
+void GrBufferAllocPool::reset() {
+    VALIDATE();
+    if (fBlocks.count()) {
+        GrGeometryBuffer* buffer = fBlocks.back().fBuffer;
+        if (buffer->isLocked()) {
+            buffer->unlock();
+        }
+    }
+    while (!fBlocks.empty()) {
+        destroyBlock();
+    }
+    if (fPreallocBuffers.count()) {
+        // must set this after above loop.
+        fFirstPreallocBuffer = (fFirstPreallocBuffer + fPreallocBuffersInUse) %
+                               fPreallocBuffers.count();
+    }
+    fCpuData.realloc(fGpu->supportsBufferLocking() ? 0 : fMinBlockSize);
+    GrAssert(0 == fPreallocBuffersInUse);
+    VALIDATE();
+}
+
+void GrBufferAllocPool::unlock() {
+    VALIDATE();
+
+    if (NULL != fBufferPtr) {
+        BufferBlock& block = fBlocks.back();
+        if (block.fBuffer->isLocked()) {
+            block.fBuffer->unlock();
+        } else {
+            size_t flushSize = block.fBuffer->size() - block.fBytesFree;
+            flushCpuData(fBlocks.back().fBuffer, flushSize);
+        }
+        fBufferPtr = NULL;
+    }
+    VALIDATE();
+}
+
+#if GR_DEBUG
+void GrBufferAllocPool::validate() const {
+    if (NULL != fBufferPtr) {
+        GrAssert(!fBlocks.empty());
+        if (fBlocks.back().fBuffer->isLocked()) {
+            GrGeometryBuffer* buf = fBlocks.back().fBuffer;
+            GrAssert(buf->lockPtr() == fBufferPtr);
+        } else {
+            GrAssert(fCpuData.get() == fBufferPtr);
+            GrAssert(fCpuData.size() == fBlocks.back().fBuffer->size());
+        }
+    } else {
+        GrAssert(fBlocks.empty() || !fBlocks.back().fBuffer->isLocked());
+    }
+    for (int i = 0; i < fBlocks.count() - 1; ++i) {
+        GrAssert(!fBlocks[i].fBuffer->isLocked());
+    }
+}
+#endif
+
+void* GrBufferAllocPool::makeSpace(size_t size,
+                                   size_t alignment,
+                                   const GrGeometryBuffer** buffer,
+                                   size_t* offset) {
+    VALIDATE();
+
+    GrAssert(NULL != buffer);
+    GrAssert(NULL != offset);
+
+    if (NULL != fBufferPtr) {
+        BufferBlock& back = fBlocks.back();
+        size_t usedBytes = back.fBuffer->size() - back.fBytesFree;
+        size_t pad = GrSizeAlignUpPad(usedBytes,
+                                      alignment);
+        if ((size + pad) <= back.fBytesFree) {
+            usedBytes += pad;
+            *offset = usedBytes;
+            *buffer = back.fBuffer;
+            back.fBytesFree -= size + pad;
+            return (void*)(reinterpret_cast<intptr_t>(fBufferPtr) + usedBytes);
+        }
+    }
+
+    if (!createBlock(size)) {
+        return NULL;
+    }
+    VALIDATE();
+    GrAssert(NULL != fBufferPtr);
+
+    *offset = 0;
+    BufferBlock& back = fBlocks.back();
+    *buffer = back.fBuffer;
+    back.fBytesFree -= size;
+    return fBufferPtr;
+}
+
+int GrBufferAllocPool::currentBufferItems(size_t itemSize) const {
+    VALIDATE();
+    if (NULL != fBufferPtr) {
+        const BufferBlock& back = fBlocks.back();
+        size_t usedBytes = back.fBuffer->size() - back.fBytesFree;
+        size_t pad = GrSizeAlignUpPad(usedBytes, itemSize);
+        return (back.fBytesFree - pad) / itemSize;
+    } else if (fPreallocBuffersInUse < fPreallocBuffers.count()) {
+        return fMinBlockSize / itemSize;
+    }
+    return 0;
+}
+
+int GrBufferAllocPool::preallocatedBuffersRemaining() const {
+    return fPreallocBuffers.count() - fPreallocBuffersInUse;
+}
+
+int GrBufferAllocPool::preallocatedBufferCount() const {
+    return fPreallocBuffers.count();
+}
+
+void GrBufferAllocPool::putBack(size_t bytes) {
+    VALIDATE();
+    if (NULL != fBufferPtr) {
+        BufferBlock& back = fBlocks.back();
+        size_t bytesUsed = back.fBuffer->size() - back.fBytesFree;
+        if (bytes >= bytesUsed) {
+            destroyBlock();
+            bytes -= bytesUsed;
+        } else {
+            back.fBytesFree += bytes;
+            return;
+        }
+    }
+    VALIDATE();
+    GrAssert(NULL == fBufferPtr);
+    // we don't partially roll-back buffers because our VB semantics say locking
+    // a VB discards its previous content.
+    // We could honor it by being sure we use updateSubData and not lock
+    // we will roll-back fully released buffers, though.
+    while (!fBlocks.empty() &&
+           bytes >= fBlocks.back().fBuffer->size()) {
+        bytes -= fBlocks.back().fBuffer->size();
+        destroyBlock();
+    }
+    VALIDATE();
+}
+
+bool GrBufferAllocPool::createBlock(size_t requestSize) {
+
+    size_t size = GrMax(requestSize, fMinBlockSize);
+    GrAssert(size >= GrBufferAllocPool_MIN_BLOCK_SIZE);
+
+    VALIDATE();
+
+    BufferBlock& block = fBlocks.push_back();
+
+    if (size == fMinBlockSize &&
+        fPreallocBuffersInUse < fPreallocBuffers.count()) {
+
+        uint32_t nextBuffer = (fPreallocBuffersInUse + fFirstPreallocBuffer) %
+                               fPreallocBuffers.count();
+        block.fBuffer = fPreallocBuffers[nextBuffer];
+        block.fBuffer->ref();
+        ++fPreallocBuffersInUse;
+    } else {
+        block.fBuffer = this->createBuffer(size);
+        if (NULL == block.fBuffer) {
+            fBlocks.pop_back();
+            return false;
+        }
+    }
+
+    block.fBytesFree = size;
+    if (NULL != fBufferPtr) {
+        GrAssert(fBlocks.count() > 1);
+        BufferBlock& prev = fBlocks.fromBack(1);
+        if (prev.fBuffer->isLocked()) {
+            prev.fBuffer->unlock();
+        } else {
+            flushCpuData(prev.fBuffer,
+                         prev.fBuffer->size() - prev.fBytesFree);
+        }
+        fBufferPtr = NULL;
+    }
+
+    GrAssert(NULL == fBufferPtr);
+
+    if (fGpu->supportsBufferLocking() &&
+        size > GR_GEOM_BUFFER_LOCK_THRESHOLD &&
+        (!fFrequentResetHint || requestSize > GR_GEOM_BUFFER_LOCK_THRESHOLD)) {
+        fBufferPtr = block.fBuffer->lock();
+    }
+
+    if (NULL == fBufferPtr) {
+        fBufferPtr = fCpuData.realloc(size);
+    }
+
+    VALIDATE();
+
+    return true;
+}
+
+void GrBufferAllocPool::destroyBlock() {
+    GrAssert(!fBlocks.empty());
+
+    BufferBlock& block = fBlocks.back();
+    if (fPreallocBuffersInUse > 0) {
+        uint32_t prevPreallocBuffer = (fPreallocBuffersInUse +
+                                       fFirstPreallocBuffer +
+                                       (fPreallocBuffers.count() - 1)) %
+                                      fPreallocBuffers.count();
+        if (block.fBuffer == fPreallocBuffers[prevPreallocBuffer]) {
+            --fPreallocBuffersInUse;
+        }
+    }
+    GrAssert(!block.fBuffer->isLocked());
+    block.fBuffer->unref();
+    fBlocks.pop_back();
+    fBufferPtr = NULL;
+}
+
+void GrBufferAllocPool::flushCpuData(GrGeometryBuffer* buffer,
+                                     size_t flushSize) {
+    GrAssert(NULL != buffer);
+    GrAssert(!buffer->isLocked());
+    GrAssert(fCpuData.get() == fBufferPtr);
+    GrAssert(fCpuData.size() == buffer->size());
+    GrAssert(flushSize <= buffer->size());
+
+    bool updated = false;
+    if (fGpu->supportsBufferLocking() &&
+        flushSize > GR_GEOM_BUFFER_LOCK_THRESHOLD) {
+        void* data = buffer->lock();
+        if (NULL != data) {
+            memcpy(data, fBufferPtr, flushSize);
+            buffer->unlock();
+            updated = true;
+        }
+    }
+    buffer->updateData(fBufferPtr, flushSize);
+}
+
+GrGeometryBuffer* GrBufferAllocPool::createBuffer(size_t size) {
+    if (kIndex_BufferType == fBufferType) {
+        return fGpu->createIndexBuffer(size, true);
+    } else {
+        GrAssert(kVertex_BufferType == fBufferType);
+        return fGpu->createVertexBuffer(size, true);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrVertexBufferAllocPool::GrVertexBufferAllocPool(GrGpu* gpu,
+                                                 bool frequentResetHint,
+                                                 size_t bufferSize,
+                                                 int preallocBufferCnt)
+: GrBufferAllocPool(gpu,
+                    kVertex_BufferType,
+                    frequentResetHint,
+                    bufferSize,
+                    preallocBufferCnt) {
+}
+
+void* GrVertexBufferAllocPool::makeSpace(GrVertexLayout layout,
+                                         int vertexCount,
+                                         const GrVertexBuffer** buffer,
+                                         int* startVertex) {
+
+    GrAssert(vertexCount >= 0);
+    GrAssert(NULL != buffer);
+    GrAssert(NULL != startVertex);
+
+    size_t vSize = GrDrawTarget::VertexSize(layout);
+    size_t offset;
+    const GrGeometryBuffer* geomBuffer;
+    void* ptr = INHERITED::makeSpace(vSize * vertexCount,
+                                     vSize,
+                                     &geomBuffer,
+                                     &offset);
+
+    *buffer = (const GrVertexBuffer*) geomBuffer;
+    GrAssert(0 == offset % vSize);
+    *startVertex = offset / vSize;
+    return ptr;
+}
+
+bool GrVertexBufferAllocPool::appendVertices(GrVertexLayout layout,
+                                             int vertexCount,
+                                             const void* vertices,
+                                             const GrVertexBuffer** buffer,
+                                             int* startVertex) {
+    void* space = makeSpace(layout, vertexCount, buffer, startVertex);
+    if (NULL != space) {
+        memcpy(space,
+               vertices,
+               GrDrawTarget::VertexSize(layout) * vertexCount);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+int GrVertexBufferAllocPool::preallocatedBufferVertices(GrVertexLayout layout) const {
+    return INHERITED::preallocatedBufferSize() /
+            GrDrawTarget::VertexSize(layout);
+}
+
+int GrVertexBufferAllocPool::currentBufferVertices(GrVertexLayout layout) const {
+    return currentBufferItems(GrDrawTarget::VertexSize(layout));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrIndexBufferAllocPool::GrIndexBufferAllocPool(GrGpu* gpu,
+                                               bool frequentResetHint,
+                                               size_t bufferSize,
+                                               int preallocBufferCnt)
+: GrBufferAllocPool(gpu,
+                    kIndex_BufferType,
+                    frequentResetHint,
+                    bufferSize,
+                    preallocBufferCnt) {
+}
+
+void* GrIndexBufferAllocPool::makeSpace(int indexCount,
+                                        const GrIndexBuffer** buffer,
+                                        int* startIndex) {
+
+    GrAssert(indexCount >= 0);
+    GrAssert(NULL != buffer);
+    GrAssert(NULL != startIndex);
+
+    size_t offset;
+    const GrGeometryBuffer* geomBuffer;
+    void* ptr = INHERITED::makeSpace(indexCount * sizeof(uint16_t),
+                                     sizeof(uint16_t),
+                                     &geomBuffer,
+                                     &offset);
+
+    *buffer = (const GrIndexBuffer*) geomBuffer;
+    GrAssert(0 == offset % sizeof(uint16_t));
+    *startIndex = offset / sizeof(uint16_t);
+    return ptr;
+}
+
+bool GrIndexBufferAllocPool::appendIndices(int indexCount,
+                                           const void* indices,
+                                           const GrIndexBuffer** buffer,
+                                           int* startIndex) {
+    void* space = makeSpace(indexCount, buffer, startIndex);
+    if (NULL != space) {
+        memcpy(space, indices, sizeof(uint16_t) * indexCount);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+int GrIndexBufferAllocPool::preallocatedBufferIndices() const {
+    return INHERITED::preallocatedBufferSize() / sizeof(uint16_t);
+}
+
+int GrIndexBufferAllocPool::currentBufferIndices() const {
+    return currentBufferItems(sizeof(uint16_t));
+}
diff --git a/gpu/src/GrBufferAllocPool.h b/gpu/src/GrBufferAllocPool.h
new file mode 100644
index 0000000..80f16ab
--- /dev/null
+++ b/gpu/src/GrBufferAllocPool.h
@@ -0,0 +1,349 @@
+/*
+    Copyright 2010 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+
+#ifndef GrBufferAllocPool_DEFINED
+#define GrBufferAllocPool_DEFINED
+
+#include "GrNoncopyable.h"
+#include "GrTDArray.h"
+#include "GrTArray.h"
+#include "GrMemory.h"
+
+class GrGeometryBuffer;
+class GrGpu;
+
+/**
+ * A pool of geometry buffers tied to a GrGpu.
+ *
+ * The pool allows a client to make space for geometry and then put back excess
+ * space if it over allocated. When a client is ready to draw from the pool
+ * it calls unlock on the pool ensure buffers are ready for drawing. The pool
+ * can be reset after drawing is completed to recycle space.
+ *
+ * At creation time a minimum per-buffer size can be specified. Additionally,
+ * a number of buffers to preallocate can be specified. These will
+ * be allocated at the min size and kept around until the pool is destroyed.
+ */
+class GrBufferAllocPool : GrNoncopyable {
+protected:
+
+    // We could make the createBuffer a virtual except that we want to use it
+    // in the cons for pre-allocated buffers.
+    enum BufferType {
+        kVertex_BufferType,
+        kIndex_BufferType,
+    };
+
+    /**
+     * Constructor
+     *
+     * @param gpu                   The GrGpu used to create the buffers.
+     * @param bufferType            The type of buffers to create.
+     * @param frequentResetHint     A hint that indicates that the pool
+     *                              should expect frequent unlock() calls
+     *                              (as opposed to many makeSpace / acquires
+     *                              between resets).
+     * @param bufferSize            The minimum size of created buffers.
+     *                              This value will be clamped to some
+     *                              reasonable minimum.
+     * @param preallocBufferCnt     The pool will allocate this number of
+     *                              buffers at bufferSize and keep them until it
+     *                              is destroyed.
+     */
+     GrBufferAllocPool(GrGpu* gpu,
+                       BufferType bufferType,
+                       bool frequentResetHint,
+                       size_t   bufferSize = 0,
+                       int preallocBufferCnt = 0);
+
+    virtual ~GrBufferAllocPool();
+
+public:
+    /**
+     * Ensures all buffers are unlocked and have all data written to them.
+     * Call before drawing using buffers from the pool.
+     */
+    void unlock();
+
+    /**
+     *  Invalidates all the data in the pool, unrefs non-preallocated buffers.
+     */
+    void reset();
+
+    /**
+     * Gets the number of preallocated buffers that are yet to be used.
+     */
+    int preallocatedBuffersRemaining() const;
+
+    /**
+     * gets the number of preallocated buffers
+     */
+    int preallocatedBufferCount() const;
+
+
+    /**
+     * Frees data from makeSpaces in LIFO order.
+     */
+    void putBack(size_t bytes);
+
+    /**
+     * Gets the GrGpu that this pool is associated with.
+     */
+    GrGpu* getGpu() { return fGpu; }
+
+protected:
+    /**
+     * Gets the size of the preallocated buffers.
+     *
+     * @return the size of preallocated buffers.
+     */
+    size_t preallocatedBufferSize() const {
+        return fPreallocBuffers.count() ? fMinBlockSize : 0;
+    }
+
+    /**
+     * Returns a block of memory to hold data. A buffer designated to hold the
+     * data is given to the caller. The buffer may or may not be locked. The
+     * returned ptr remains valid until any of the following:
+     *      *makeSpace is called again.
+     *      *unlock is called.
+     *      *reset is called.
+     *      *this object is destroyed.
+     *
+     * Once unlock on the pool is called the data is guaranteed to be in the
+     * buffer at the offset indicated by offset. Until that time it may be
+     * in temporary storage and/or the buffer may be locked.
+     *
+     * @param size         the amount of data to make space for
+     * @param alignment    alignment constraint from start of buffer
+     * @param buffer       returns the buffer that will hold the data.
+     * @param offset       returns the offset into buffer of the data.
+     * @return pointer to where the client should write the data.
+     */
+    void* makeSpace(size_t size,
+                    size_t alignment,
+                    const GrGeometryBuffer** buffer,
+                    size_t* offset);
+
+    /**
+     * Gets the number of items of a size that can be added to the current
+     * buffer without spilling to another buffer. If the pool has been reset, or
+     * the previous makeSpace completely exhausted a buffer then the returned
+     * size will be the size of the next available preallocated buffer, or zero
+     * if no preallocated buffer remains available. It is assumed that items
+     * should be itemSize-aligned from the start of a buffer.
+     *
+     * @return the number of items that would fit in the current buffer.
+     */
+    int currentBufferItems(size_t itemSize) const;
+
+    GrGeometryBuffer* createBuffer(size_t size);
+
+private:
+
+    struct BufferBlock {
+        size_t              fBytesFree;
+        GrGeometryBuffer*   fBuffer;
+    };
+
+    bool createBlock(size_t requestSize);
+    void destroyBlock();
+    void flushCpuData(GrGeometryBuffer* buffer, size_t flushSize);
+#if GR_DEBUG
+    void validate() const;
+#endif
+
+    GrGpu*                          fGpu;
+    bool                            fFrequentResetHint;
+    GrTDArray<GrGeometryBuffer*>    fPreallocBuffers;
+    size_t                          fMinBlockSize;
+    BufferType                      fBufferType;
+
+    GrTArray<BufferBlock>           fBlocks;
+    int                             fPreallocBuffersInUse;
+    int                             fFirstPreallocBuffer;
+    GrAutoMalloc                    fCpuData;
+    void*                       	fBufferPtr;
+};
+
+class GrVertexBuffer;
+
+/**
+ * A GrBufferAllocPool of vertex buffers
+ */
+class GrVertexBufferAllocPool : public GrBufferAllocPool {
+public:
+    /**
+     * Constructor
+     *
+     * @param gpu                   The GrGpu used to create the vertex buffers.
+     * @param frequentResetHint     A hint that indicates that the pool
+     *                              should expect frequent unlock() calls
+     *                              (as opposed to many makeSpace / acquires
+     *                              between resets).
+     * @param bufferSize            The minimum size of created VBs This value
+     *                              will be clamped to some reasonable minimum.
+     * @param preallocBufferCnt     The pool will allocate this number of VBs at
+     *                              bufferSize and keep them until it is
+     *                              destroyed.
+     */
+    GrVertexBufferAllocPool(GrGpu* gpu,
+                            bool frequentResetHint,
+                            size_t bufferSize = 0,
+                            int preallocBufferCnt = 0);
+
+    /**
+     * Returns a block of memory to hold vertices. A buffer designated to hold
+     * the vertices given to the caller. The buffer may or may not be locked.
+     * The returned ptr remains valid until any of the following:
+     *      *makeSpace is called again.
+     *      *unlock is called.
+     *      *reset is called.
+     *      *this object is destroyed.
+     *
+     * Once unlock on the pool is called the vertices are guaranteed to be in
+     * the buffer at the offset indicated by startVertex. Until that time they
+     * may be in temporary storage and/or the buffer may be locked.
+     *
+     * @param layout       specifies type of vertices to allocate space for
+     * @param vertexCount  number of vertices to allocate space for
+     * @param buffer       returns the vertex buffer that will hold the
+     *                     vertices.
+     * @param startVertex  returns the offset into buffer of the first vertex.
+     *                     In units of the size of a vertex from layout param.
+     * @return pointer to first vertex.
+     */
+    void* makeSpace(GrVertexLayout layout,
+                    int vertexCount,
+                    const GrVertexBuffer** buffer,
+                    int* startVertex);
+
+    /**
+     * Shortcut to make space and then write verts into the made space.
+     */
+    bool appendVertices(GrVertexLayout layout,
+                        int vertexCount,
+                        const void* vertices,
+                        const GrVertexBuffer** buffer,
+                        int* startVertex);
+
+    /**
+     * Gets the number of vertices that can be added to the current VB without
+     * spilling to another VB. If the pool has been reset, or the previous
+     * makeSpace completely exhausted a VB then the returned number of vertices
+     * would fit in the next available preallocated buffer. If any makeSpace
+     * would force a new VB to be created the return value will be zero.
+     *
+     * @param   the format of vertices to compute space for.
+     * @return the number of vertices that would fit in the current buffer.
+     */
+    int currentBufferVertices(GrVertexLayout layout) const;
+
+    /**
+     * Gets the number of vertices that can fit in a  preallocated vertex buffer.
+     * Zero if no preallocated buffers.
+     *
+     * @param   the format of vertices to compute space for.
+     *
+     * @return number of vertices that fit in one of the preallocated vertex
+     *         buffers.
+     */
+    int preallocatedBufferVertices(GrVertexLayout layout) const;
+
+private:
+    typedef GrBufferAllocPool INHERITED;
+};
+
+class GrIndexBuffer;
+
+/**
+ * A GrBufferAllocPool of index buffers
+ */
+class GrIndexBufferAllocPool : public GrBufferAllocPool {
+public:
+    /**
+     * Constructor
+     *
+     * @param gpu                   The GrGpu used to create the index buffers.
+     * @param frequentResetHint     A hint that indicates that the pool
+     *                              should expect frequent unlock() calls
+     *                              (as opposed to many makeSpace / acquires
+     *                              between resets).
+     * @param bufferSize            The minimum size of created IBs This value
+     *                              will be clamped to some reasonable minimum.
+     * @param preallocBufferCnt     The pool will allocate this number of VBs at
+     *                              bufferSize and keep them until it is
+     *                              destroyed.
+     */
+    GrIndexBufferAllocPool(GrGpu* gpu,
+                           bool frequentResetHint,
+                           size_t bufferSize = 0,
+                           int preallocBufferCnt = 0);
+
+    /**
+     * Returns a block of memory to hold indices. A buffer designated to hold
+     * the indices is given to the caller. The buffer may or may not be locked.
+     * The returned ptr remains valid until any of the following:
+     *      *makeSpace is called again.
+     *      *unlock is called.
+     *      *reset is called.
+     *      *this object is destroyed.
+     *
+     * Once unlock on the pool is called the indices are guaranteed to be in the
+     * buffer at the offset indicated by startIndex. Until that time they may be
+     * in temporary storage and/or the buffer may be locked.
+     *
+     * @param indexCount   number of indices to allocate space for
+     * @param buffer       returns the index buffer that will hold the indices.
+     * @param startIndex   returns the offset into buffer of the first index.
+     * @return pointer to first index.
+     */
+    void* makeSpace(int indexCount,
+                    const GrIndexBuffer** buffer,
+                    int* startIndex);
+
+    /**
+     * Shortcut to make space and then write indices into the made space.
+     */
+    bool appendIndices(int indexCount,
+                       const void* indices,
+                       const GrIndexBuffer** buffer,
+                       int* startIndex);
+
+    /**
+     * Gets the number of indices that can be added to the current IB without
+     * spilling to another IB. If the pool has been reset, or the previous
+     * makeSpace completely exhausted a IB then the returned number of indices
+     * would fit in the next available preallocated buffer. If any makeSpace
+     * would force a new IB to be created the return value will be zero.
+     */
+    int currentBufferIndices() const;
+
+    /**
+     * Gets the number of indices that can fit in a preallocated index buffer.
+     * Zero if no preallocated buffers.
+     *
+     * @return number of indices that fit in one of the preallocated index
+     *         buffers.
+     */
+    int preallocatedBufferIndices() const;
+
+private:
+    typedef GrBufferAllocPool INHERITED;
+};
+
+#endif
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index e224891..d14777e 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -14,7 +14,6 @@
     limitations under the License.

  */

 

-

 #include "GrContext.h"

 #include "GrTypes.h"

 #include "GrTextureCache.h"

@@ -23,23 +22,16 @@
 #include "GrPathIter.h"

 #include "GrClipIterator.h"

 #include "GrIndexBuffer.h"

+#include "GrInOrderDrawBuffer.h"

+#include "GrBufferAllocPool.h"

 

 #define DEFER_TEXT_RENDERING 1

 

 static const size_t MAX_TEXTURE_CACHE_COUNT = 128;

 static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;

 

-#if DEFER_TEXT_RENDERING

-    static const uint32_t POOL_VB_SIZE = 2048 *

-            GrDrawTarget::VertexSize(

-                GrDrawTarget::kTextFormat_VertexLayoutBit |

-                GrDrawTarget::StageTexCoordVertexLayoutBit(0,0));

-    static const uint32_t NUM_POOL_VBS = 8;

-#else

-    static const uint32_t POOL_VB_SIZE = 0;

-    static const uint32_t NUM_POOL_VBS = 0;

-

-#endif

+static const uint32_t TEXT_POOL_VB_SIZE = 1 << 18; // enough to draw 4K untextured glyphs

+static const uint32_t NUM_TEXT_POOL_VBS = 4;

 

 GrContext* GrContext::Create(GrGpu::Engine engine,

                              GrGpu::Platform3DContext context3D) {

@@ -60,6 +52,9 @@
     fGpu->unref();

     delete fTextureCache;

     delete fFontCache;

+    delete fTextDrawBuffer;

+    delete fTextVBAllocPool;

+    delete fTextIBAllocPool;

 }

 

 void GrContext::abandonAllTextures() {

@@ -487,7 +482,7 @@
                              const uint16_t indices[],

                              int indexCount) {

     GrVertexLayout layout = 0;

-    bool interLeave = false;

+    int vertexSize = sizeof(GrPoint);

 

     GrDrawTarget::AutoReleaseGeometry geo;

 

@@ -498,18 +493,16 @@
             layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);

         } else {

             layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);

-            interLeave = true;

+            vertexSize += sizeof(GrPoint);

         }

     }

 

     if (NULL != colors) {

         layout |= GrDrawTarget::kColor_VertexLayoutBit;

+        vertexSize += sizeof(GrColor);

     }

 

-    static const GrVertexLayout interleaveMask =

-        (GrDrawTarget::StageTexCoordVertexLayoutBit(0,0) |

-         GrDrawTarget::kColor_VertexLayoutBit);

-    if (interleaveMask & layout) {

+    if (sizeof(GrPoint) != vertexSize) {

         if (!geo.set(fGpu, layout, vertexCount, 0)) {

             GrPrintf("Failed to get space for vertices!");

             return;

@@ -533,11 +526,11 @@
             curVertex = (void*)((intptr_t)curVertex + vsize);

         }

     } else {

-        fGpu->setVertexSourceToArray(positions, layout);

+        fGpu->setVertexSourceToArray(layout, positions, vertexCount);

     }

 

     if (NULL != indices) {

-        fGpu->setIndexSourceToArray(indices);

+        fGpu->setIndexSourceToArray(indices, indexCount);

         fGpu->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);

     } else {

         fGpu->drawNonIndexed(primitiveType, 0, vertexCount);

@@ -816,7 +809,7 @@
             }

             case GrPathIter::kCubic_Command: {

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

-                                      tolSqd, &vert, 

+                                      tolSqd, &vert,

                                       cubic_point_count(pts, tol));

                 break;

             }

@@ -892,8 +885,10 @@
 }

 

 void GrContext::flushText() {

-    fTextDrawBuffer.playback(fGpu);

-    fTextDrawBuffer.reset();

+    if (NULL != fTextDrawBuffer) {

+        fTextDrawBuffer->playback(fGpu);

+        fTextDrawBuffer->reset();

+    }

 }

 

 bool GrContext::readPixels(int left, int top, int width, int height,

@@ -1026,16 +1021,28 @@
     fGpu->printStats();

 }

 

-GrContext::GrContext(GrGpu* gpu) :

-        fVBAllocPool(gpu,

-                     gpu->supportsBufferLocking() ? POOL_VB_SIZE : 0,

-                     gpu->supportsBufferLocking() ? NUM_POOL_VBS : 0),

-        fTextDrawBuffer(gpu->supportsBufferLocking() ? &fVBAllocPool : NULL) {

+GrContext::GrContext(GrGpu* gpu) {

     fGpu = gpu;

     fGpu->ref();

     fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,

                                        MAX_TEXTURE_CACHE_BYTES);

     fFontCache = new GrFontCache(fGpu);

+

+#if DEFER_TEXT_RENDERING

+    fTextVBAllocPool = new GrVertexBufferAllocPool(gpu,

+                                                   false,

+                                                   TEXT_POOL_VB_SIZE,

+                                                   NUM_TEXT_POOL_VBS);

+    fTextIBAllocPool = new GrIndexBufferAllocPool(gpu, false, 0, 0);

+

+    fTextDrawBuffer = new GrInOrderDrawBuffer(fTextVBAllocPool,

+                                              fTextIBAllocPool);

+#else

+    fTextDrawBuffer = NULL;

+    fTextVBAllocPool = NULL;

+    fTextIBAllocPool = NULL;

+#endif

+

 }

 

 bool GrContext::finalizeTextureKey(GrTextureKey* key,

@@ -1063,8 +1070,8 @@
 GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {

     GrDrawTarget* target;

 #if DEFER_TEXT_RENDERING

-    fTextDrawBuffer.initializeDrawStateAndClip(*fGpu);

-    target = &fTextDrawBuffer;

+    fTextDrawBuffer->initializeDrawStateAndClip(*fGpu);

+    target = fTextDrawBuffer;

 #else

     target = fGpu;

 #endif

diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 0f31e9a..5cfc6f4 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -458,20 +458,22 @@
     fReservedGeometry.fLocked = false;
 }
 
-void GrDrawTarget::setVertexSourceToArray(const void* array,
-                                          GrVertexLayout vertexLayout) {
-    fGeometrySrc.fVertexSrc    = kArray_GeometrySrcType;
-    fGeometrySrc.fVertexArray  = array;
+void GrDrawTarget::setVertexSourceToArray(GrVertexLayout vertexLayout,
+                                          const void* vertexArray,
+                                          int vertexCount) {
+    fGeometrySrc.fVertexSrc = kArray_GeometrySrcType;
     fGeometrySrc.fVertexLayout = vertexLayout;
+    setVertexSourceToArrayHelper(vertexArray, vertexCount);
 }
 
-void GrDrawTarget::setIndexSourceToArray(const void* array) {
-    fGeometrySrc.fIndexSrc   = kArray_GeometrySrcType;
-    fGeometrySrc.fIndexArray = array;
+void GrDrawTarget::setIndexSourceToArray(const void* indexArray,
+                                         int indexCount) {
+    fGeometrySrc.fIndexSrc = kArray_GeometrySrcType;
+    setIndexSourceToArrayHelper(indexArray, indexCount);
 }
 
-void GrDrawTarget::setVertexSourceToBuffer(const GrVertexBuffer* buffer,
-                                           GrVertexLayout vertexLayout) {
+void GrDrawTarget::setVertexSourceToBuffer(GrVertexLayout vertexLayout,
+                                           const GrVertexBuffer* buffer) {
     fGeometrySrc.fVertexSrc    = kBuffer_GeometrySrcType;
     fGeometrySrc.fVertexBuffer = buffer;
     fGeometrySrc.fVertexLayout = vertexLayout;
diff --git a/gpu/src/GrGLIndexBuffer.cpp b/gpu/src/GrGLIndexBuffer.cpp
index 82cffaa..2dc4154 100644
--- a/gpu/src/GrGLIndexBuffer.cpp
+++ b/gpu/src/GrGLIndexBuffer.cpp
@@ -18,18 +18,14 @@
 #include "GrGLIndexBuffer.h"
 #include "GrGpuGL.h"
 
-GrGLIndexBuffer::GrGLIndexBuffer(GLuint id, GrGpuGL* gl, uint32_t sizeInBytes,
-                                   bool dynamic) : 
+GrGLIndexBuffer::GrGLIndexBuffer(GLuint id, GrGpuGL* gl, size_t sizeInBytes,
+                                   bool dynamic) :
                                 INHERITED(sizeInBytes, dynamic),
                                 fGL(gl),
                                 fBufferID(id),
                                 fLockPtr(NULL) {
 }
 
-GLuint GrGLIndexBuffer::bufferID() const {
-    return fBufferID;
-}
-
 GrGLIndexBuffer::~GrGLIndexBuffer() {
     // make sure we've not been abandoned
     if (fBufferID) {
@@ -38,8 +34,17 @@
     }
 }
 
+void GrGLIndexBuffer::bind() const {
+    GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, fBufferID));
+    fGL->notifyIndexBufferBind(this);
+}
+
+GLuint GrGLIndexBuffer::bufferID() const {
+    return fBufferID;
+}
+
 void GrGLIndexBuffer::abandon() {
-    fBufferID = 0; 
+    fBufferID = 0;
     fGL = NULL;
     fLockPtr = NULL;
 }
@@ -48,12 +53,9 @@
     GrAssert(fBufferID);
     GrAssert(!isLocked());
     if (fGL->supportsBufferLocking()) {
-        GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, fBufferID));
-        fGL->notifyIndexBufferBind(this);
-        // call bufferData with null ptr to allow driver to perform renaming
-        // If this call is removed revisit updateData to be sure it doesn't
-        // leave buffer undersized (as it currently does).
-        GR_GL(BufferData(GL_ELEMENT_ARRAY_BUFFER, size(), NULL, 
+        bind();
+        // Let driver know it can discard the old data
+        GR_GL(BufferData(GL_ELEMENT_ARRAY_BUFFER, size(), NULL,
                          dynamic() ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
         fLockPtr = GR_GLEXT(fGL->extensions(),
                             MapBuffer(GL_ELEMENT_ARRAY_BUFFER, GR_WRITE_ONLY));
@@ -63,27 +65,27 @@
     return NULL;
 }
 
+void* GrGLIndexBuffer::lockPtr() const {
+    return fLockPtr;
+}
+
 void GrGLIndexBuffer::unlock() {
     GrAssert(fBufferID);
     GrAssert(isLocked());
+    GrAssert(fGL->supportsBufferLocking());
 
-    if (fGL->supportsBufferLocking()) {
-        GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, fBufferID));
-        fGL->notifyIndexBufferBind(this);
-        GR_GLEXT(fGL->extensions(),
-                 UnmapBuffer(GL_ELEMENT_ARRAY_BUFFER));
-        fLockPtr = NULL;
-    }
+    bind();
+    GR_GLEXT(fGL->extensions(), UnmapBuffer(GL_ELEMENT_ARRAY_BUFFER));
+    fLockPtr = NULL;
 }
 
 bool GrGLIndexBuffer::isLocked() const {
     GrAssert(fBufferID);
 #if GR_DEBUG
     if (fGL->supportsBufferLocking()) {
+        bind();
         GLint mapped;
-        GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, fBufferID));
-        fGL->notifyIndexBufferBind(this);
-        GR_GL(GetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, 
+        GR_GL(GetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER,
                                    GR_BUFFER_MAPPED, &mapped));
         GrAssert(!!mapped == !!fLockPtr);
     }
@@ -91,16 +93,33 @@
     return NULL != fLockPtr;
 }
 
-bool GrGLIndexBuffer::updateData(const void* src, uint32_t srcSizeInBytes) {
+bool GrGLIndexBuffer::updateData(const void* src, size_t srcSizeInBytes) {
     GrAssert(fBufferID);
     GrAssert(!isLocked());
     if (srcSizeInBytes > size()) {
         return false;
     }
-    GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, fBufferID));
-    fGL->notifyIndexBufferBind(this);
-    GR_GL(BufferData(GL_ELEMENT_ARRAY_BUFFER, srcSizeInBytes, src, 
-                     dynamic() ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
+    bind();
+    GLenum usage = dynamic() ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW;
+    if (size() == srcSizeInBytes) {
+        GR_GL(BufferData(GL_ELEMENT_ARRAY_BUFFER, srcSizeInBytes, src, usage));
+    } else {
+        GR_GL(BufferData(GL_ELEMENT_ARRAY_BUFFER, size(), NULL, usage));
+        GR_GL(BufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, srcSizeInBytes, src));
+    }
+    return true;
+}
+
+bool GrGLIndexBuffer::updateSubData(const void* src,
+                                    size_t srcSizeInBytes,
+                                    size_t offset) {
+    GrAssert(fBufferID);
+    GrAssert(!isLocked());
+    if (srcSizeInBytes + offset > size()) {
+        return false;
+    }
+    bind();
+    GR_GL(BufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, srcSizeInBytes, src));
     return true;
 }
 
diff --git a/gpu/src/GrGLVertexBuffer.cpp b/gpu/src/GrGLVertexBuffer.cpp
index b4ddc24..ec48936 100644
--- a/gpu/src/GrGLVertexBuffer.cpp
+++ b/gpu/src/GrGLVertexBuffer.cpp
@@ -18,8 +18,8 @@
 #include "GrGLVertexBuffer.h"
 #include "GrGpuGL.h"
 
-GrGLVertexBuffer::GrGLVertexBuffer(GLuint id, GrGpuGL* gl, uint32_t sizeInBytes,
-                                   bool dynamic) : 
+GrGLVertexBuffer::GrGLVertexBuffer(GLuint id, GrGpuGL* gl, size_t sizeInBytes,
+                                   bool dynamic) :
                                    INHERITED(sizeInBytes, dynamic),
                                    fGL(gl),
                                    fBufferID(id),
@@ -34,11 +34,16 @@
     }
 }
 
+void GrGLVertexBuffer::bind() const {
+    GR_GL(BindBuffer(GL_ARRAY_BUFFER, fBufferID));
+    fGL->notifyVertexBufferBind(this);
+}
+
 GLuint GrGLVertexBuffer::bufferID() const {
     return fBufferID;
 }
 
-void GrGLVertexBuffer::abandon() { 
+void GrGLVertexBuffer::abandon() {
     fBufferID = 0;
     fGL = NULL;
     fLockPtr = NULL;
@@ -48,30 +53,29 @@
     GrAssert(fBufferID);
     GrAssert(!isLocked());
     if (fGL->supportsBufferLocking()) {
-        GR_GL(BindBuffer(GL_ARRAY_BUFFER, fBufferID));
-        fGL->notifyVertexBufferBind(this);
-        // call bufferData with null ptr to allow driver to perform renaming
-        // If this call is removed revisit updateData to be sure it doesn't
-        // leave buffer undersized (as it currently does).
-        GR_GL(BufferData(GL_ARRAY_BUFFER, size(), NULL, 
+        bind();
+        // Let driver know it can discard the old data
+        GR_GL(BufferData(GL_ARRAY_BUFFER, size(), NULL,
                          dynamic() ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
         fLockPtr = GR_GLEXT(fGL->extensions(),
-                            MapBuffer(GL_ARRAY_BUFFER, GR_WRITE_ONLY)); 
+                            MapBuffer(GL_ARRAY_BUFFER, GR_WRITE_ONLY));
         return fLockPtr;
     }
     return NULL;
 }
 
+void* GrGLVertexBuffer::lockPtr() const {
+    return fLockPtr;
+}
+
 void GrGLVertexBuffer::unlock() {
     GrAssert(fBufferID);
     GrAssert(isLocked());
-    if (fGL->supportsBufferLocking()) {
-        GR_GL(BindBuffer(GL_ARRAY_BUFFER, fBufferID));
-        fGL->notifyVertexBufferBind(this);
-        GR_GLEXT(fGL->extensions(),
-                 UnmapBuffer(GL_ARRAY_BUFFER));
-        fLockPtr = NULL;
-    }
+    GrAssert(fGL->supportsBufferLocking());
+
+    bind();
+    GR_GLEXT(fGL->extensions(), UnmapBuffer(GL_ARRAY_BUFFER));
+    fLockPtr = NULL;
 }
 
 bool GrGLVertexBuffer::isLocked() const {
@@ -79,8 +83,7 @@
 #if GR_DEBUG
     if (fGL->supportsBufferLocking()) {
         GLint mapped;
-        GR_GL(BindBuffer(GL_ARRAY_BUFFER, fBufferID));
-        fGL->notifyVertexBufferBind(this);
+        bind();
         GR_GL(GetBufferParameteriv(GL_ARRAY_BUFFER, GR_BUFFER_MAPPED, &mapped));
         GrAssert(!!mapped == !!fLockPtr);
     }
@@ -88,16 +91,33 @@
     return NULL != fLockPtr;
 }
 
-bool GrGLVertexBuffer::updateData(const void* src, uint32_t srcSizeInBytes) {
+bool GrGLVertexBuffer::updateData(const void* src, size_t srcSizeInBytes) {
     GrAssert(fBufferID);
     GrAssert(!isLocked());
     if (srcSizeInBytes > size()) {
         return false;
     }
-    GR_GL(BindBuffer(GL_ARRAY_BUFFER, fBufferID));
-    fGL->notifyVertexBufferBind(this);
-    GR_GL(BufferData(GL_ARRAY_BUFFER, srcSizeInBytes, src, 
-                     dynamic() ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW));
+    bind();
+    GLenum usage = dynamic() ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW;
+    if (size() == srcSizeInBytes) {
+        GR_GL(BufferData(GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
+    } else {
+        GR_GL(BufferData(GL_ARRAY_BUFFER, size(), NULL, usage));
+        GR_GL(BufferSubData(GL_ARRAY_BUFFER, 0, srcSizeInBytes, src));
+    }
+    return true;
+}
+
+bool GrGLVertexBuffer::updateSubData(const void* src,
+                                     size_t srcSizeInBytes,
+                                     size_t offset) {
+    GrAssert(fBufferID);
+    GrAssert(!isLocked());
+    if (srcSizeInBytes + offset > size()) {
+        return false;
+    }
+    bind();
+    GR_GL(BufferSubData(GL_ARRAY_BUFFER, offset, srcSizeInBytes, src));
     return true;
 }
 
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index 057a8c9..e406f6f 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -14,7 +14,6 @@
     limitations under the License.
  */
 
-
 #include "GrGpu.h"
 #include "GrMemory.h"
 #include "GrTextStrike.h"
@@ -22,6 +21,10 @@
 #include "GrClipIterator.h"
 #include "GrIndexBuffer.h"
 #include "GrVertexBuffer.h"
+#include "GrBufferAllocPool.h"
+
+// probably makes no sense for this to be less than a page
+static size_t VERTEX_POOL_VB_SIZE = 1 << 12;
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -57,6 +60,12 @@
 extern void gr_run_unittests();
 
 GrGpu::GrGpu() : f8bitPaletteSupport(false),
+                 fCurrPoolVertexBuffer(NULL),
+                 fCurrPoolStartVertex(0),
+                 fCurrPoolIndexBuffer(NULL),
+                 fCurrPoolStartIndex(0),
+                 fVertexPool(NULL),
+                 fIndexPool(NULL),
                  fQuadIndexBuffer(NULL),
                  fUnitSquareVertexBuffer(NULL) {
 #if GR_DEBUG
@@ -68,6 +77,8 @@
 GrGpu::~GrGpu() {
     GrSafeUnref(fQuadIndexBuffer);
     GrSafeUnref(fUnitSquareVertexBuffer);
+    delete fVertexPool;
+    delete fIndexPool;
 }
 
 void GrGpu::resetContext() {
@@ -124,11 +135,11 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static const int MAX_QUADS = 512; // max possible: (1 << 14) - 1;
+static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
 
 GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
 
-static inline void fillIndices(uint16_t* indices, int quadCount) {
+static inline void fill_indices(uint16_t* indices, int quadCount) {
     for (int i = 0; i < quadCount; ++i) {
         indices[6 * i + 0] = 4 * i + 0;
         indices[6 * i + 1] = 4 * i + 1;
@@ -147,11 +158,11 @@
         if (NULL != fQuadIndexBuffer) {
             uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
             if (NULL != indices) {
-                fillIndices(indices, MAX_QUADS);
+                fill_indices(indices, MAX_QUADS);
                 fQuadIndexBuffer->unlock();
             } else {
                 indices = (uint16_t*)GrMalloc(SIZE);
-                fillIndices(indices, MAX_QUADS);
+                fill_indices(indices, MAX_QUADS);
                 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
                     fQuadIndexBuffer->unref();
                     fQuadIndexBuffer = NULL;
@@ -222,41 +233,53 @@
 
             AutoStateRestore asr(this);
             AutoGeometrySrcRestore agsr(this);
-            this->disableState(kClip_StateBit);
-            eraseStencilClip();
+
+            // We have to use setVertexSourceToBuffer (and index) in order
+            // to ensure we correctly restore the client's geom sources.
+            // We tack the clip verts onto the vertex pool but we don't
+            // use the various helper functions because of their side effects.
 
             int rectTotal = fClip.countRects();
-            static const int PtsPerRect = 4;
-            // this may be called while geometry is already reserved by the
-            // client. So we use our own vertex array where we avoid malloc
-            // if we have 4 or fewer rects.
-            GrAutoSTMalloc<PtsPerRect * 4, GrPoint> vertices(PtsPerRect *
-                                                             rectTotal);
-            this->setVertexSourceToArray(vertices.get(), 0);
+            if (NULL == fVertexPool) {
+                fVertexPool = new GrVertexBufferAllocPool(this,
+                                                          true,
+                                                          VERTEX_POOL_VB_SIZE,
+                                                          1);
+            }
+            const GrVertexBuffer* vertexBuffer;
+            int vStart;
+            GrPoint* rectVertices =
+                reinterpret_cast<GrPoint*>(fVertexPool->makeSpace(0,
+                                                                  rectTotal * 4,
+                                                                  &vertexBuffer,
+                                                                  &vStart));
+            for (int r = 0; r < rectTotal; ++r) {
+                const GrIRect& rect = fClip.getRects()[r];
+                rectVertices[4 * r].setIRectFan(rect.fLeft, rect.fTop,
+                                                rect.fRight, rect.fBottom);
+            }
+            fVertexPool->unlock();
+            this->setVertexSourceToBuffer(0, vertexBuffer);
+            this->setIndexSourceToBuffer(quadIndexBuffer());
+            this->setViewMatrix(GrMatrix::I());
+            // don't clip the clip or recurse!
+            this->disableState(kClip_StateBit);
+            this->eraseStencilClip();
+            this->setStencilPass((GrDrawTarget::StencilPass)kSetClip_StencilPass);
             int currRect = 0;
             while (currRect < rectTotal) {
                 int rectCount = GrMin(this->maxQuadsInIndexBuffer(),
                                       rectTotal - currRect);
-
-                GrPoint* verts = (GrPoint*)vertices +
-                                 (currRect * PtsPerRect);
-
-                for (int i = 0; i < rectCount; i++) {
-                    GrRect r(fClip.getRects()[i + currRect]);
-                    verts = r.setRectFan(verts);
-                }
-                this->setIndexSourceToBuffer(quadIndexBuffer());
-
-                this->setViewMatrix(GrMatrix::I());
-                this->setStencilPass((GrDrawTarget::StencilPass)kSetClip_StencilPass);
-                this->drawIndexed(GrGpu::kTriangles_PrimitiveType,
-                                  currRect * PtsPerRect, 0,
-                                  rectCount * PtsPerRect, rectCount * 6);
-
+                this->drawIndexed(kTriangles_PrimitiveType,
+                                  vStart + currRect * 4,
+                                  0,
+                                  rectCount*4,
+                                  rectCount*6);
                 currRect += rectCount;
             }
             fClipState.fStencilClipTarget = fCurrDrawState.fRenderTarget;
         }
+
         fClipState.fClipIsDirty = false;
         if (!fClipState.fClipInStencil) {
             r = &fClip.getBounds();
@@ -274,10 +297,10 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void GrGpu::drawIndexed(PrimitiveType type,
-                        uint32_t startVertex,
-                        uint32_t startIndex,
-                        uint32_t vertexCount,
-                        uint32_t indexCount) {
+                        int startVertex,
+                        int startIndex,
+                        int vertexCount,
+                        int indexCount) {
     GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
              fReservedGeometry.fLocked);
     GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
@@ -293,15 +316,17 @@
     fStats.fDrawCnt   += 1;
 #endif
 
-    setupGeometry(startVertex, startIndex, vertexCount, indexCount);
+    int sVertex = startVertex;
+    int sIndex = startIndex;
+    setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
 
-    drawIndexedHelper(type, startVertex, startIndex,
+    drawIndexedHelper(type, sVertex, sIndex,
                       vertexCount, indexCount);
 }
 
 void GrGpu::drawNonIndexed(PrimitiveType type,
-                           uint32_t startVertex,
-                           uint32_t vertexCount) {
+                           int startVertex,
+                           int vertexCount) {
     GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
              fReservedGeometry.fLocked);
 
@@ -313,37 +338,103 @@
     fStats.fDrawCnt   += 1;
 #endif
 
-    setupGeometry(startVertex, 0, vertexCount, 0);
+    int sVertex = startVertex;
+    setupGeometry(&sVertex, NULL, vertexCount, 0);
 
-    drawNonIndexedHelper(type, startVertex, vertexCount);
+    drawNonIndexedHelper(type, sVertex, vertexCount);
+}
+
+void GrGpu::finalizeReservedVertices() {
+    GrAssert(NULL != fVertexPool);
+    fVertexPool->unlock();
+}
+
+void GrGpu::finalizeReservedIndices() {
+    GrAssert(NULL != fIndexPool);
+    fIndexPool->unlock();
+}
+
+void GrGpu::prepareVertexPool() {
+    if (NULL == fVertexPool) {
+        fVertexPool = new GrVertexBufferAllocPool(this, true, VERTEX_POOL_VB_SIZE, 1);
+    } else {
+        fVertexPool->reset();
+    }
+}
+
+void GrGpu::prepareIndexPool() {
+    if (NULL == fVertexPool) {
+        fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
+    } else {
+        fIndexPool->reset();
+    }
 }
 
 bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout,
                                   void**         vertices,
                                   void**         indices) {
-    GrAssert((fReservedGeometry.fVertexCount == 0) ||
-             (NULL != vertices));
-    if (NULL != vertices) {
-        *vertices = fVertices.realloc(VertexSize(vertexLayout) *
-                                      fReservedGeometry.fVertexCount);
-        if (!*vertices && fReservedGeometry.fVertexCount) {
+    GrAssert(!fReservedGeometry.fLocked);
+    size_t reservedVertexSpace = 0;
+
+    if (fReservedGeometry.fVertexCount) {
+        GrAssert(NULL != vertices);
+
+        prepareVertexPool();
+
+        *vertices = fVertexPool->makeSpace(vertexLayout,
+                                           fReservedGeometry.fVertexCount,
+                                           &fCurrPoolVertexBuffer,
+                                           &fCurrPoolStartVertex);
+        if (NULL == *vertices) {
             return false;
         }
+        reservedVertexSpace = VertexSize(vertexLayout) *
+                              fReservedGeometry.fVertexCount;
     }
-    GrAssert((fReservedGeometry.fIndexCount == 0) ||
-             (NULL != indices));
-    if (NULL != indices) {
-        *indices =  fIndices.realloc(sizeof(uint16_t) *
-                                     fReservedGeometry.fIndexCount);
-        if (!*indices && fReservedGeometry.fIndexCount) {
+    if (fReservedGeometry.fIndexCount) {
+        GrAssert(NULL != indices);
+
+        prepareIndexPool();
+
+        *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
+                                         &fCurrPoolIndexBuffer,
+                                         &fCurrPoolStartIndex);
+        if (NULL == *indices) {
+            fVertexPool->putBack(reservedVertexSpace);
+            fCurrPoolVertexBuffer = NULL;
             return false;
         }
     }
     return true;
 }
 
-void GrGpu::releaseGeometryHelper() {
-    return;
+void GrGpu::releaseGeometryHelper() {}
+
+void GrGpu::setVertexSourceToArrayHelper(const void* vertexArray, int vertexCount) {
+    GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
+    prepareVertexPool();
+#if GR_DEBUG
+    bool success =
+#endif
+    fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
+                                vertexCount,
+                                vertexArray,
+                                &fCurrPoolVertexBuffer,
+                                &fCurrPoolStartVertex);
+    GR_DEBUGASSERT(success);
+}
+
+void GrGpu::setIndexSourceToArrayHelper(const void* indexArray, int indexCount) {
+    GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
+    prepareIndexPool();
+#if GR_DEBUG
+    bool success =
+#endif
+    fIndexPool->appendIndices(indexCount,
+                              indexArray,
+                              &fCurrPoolIndexBuffer,
+                              &fCurrPoolStartIndex);
+    GR_DEBUGASSERT(success);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index 0b5927a..8d00af9 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -87,13 +87,6 @@
 
 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);
@@ -229,7 +222,6 @@
         GrPrintf("Single Stencil Pass For Winding: %s\n", (fSingleStencilPassForWinding ? "YES" : "NO"));
     }
 
-
 #if GR_SUPPORT_GLDESKTOP
     fRGBA8Renderbuffer = true;
 #else
@@ -251,6 +243,7 @@
 #else
     fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
 #endif
+
     if (gPrintStartupSpew) {
         GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
     }
@@ -372,10 +365,6 @@
 }
 
 GrGpuGL::~GrGpuGL() {
-#if GR_GL_NO_CLIENT_SIDE_ARRAYS
-    GrSafeUnref(fClientArrayVB);
-    GrSafeUnref(fClientArrayIB);
-#endif
 }
 
 void GrGpuGL::resetContextHelper() {
@@ -430,6 +419,8 @@
     fHWDrawState.fReverseFill = false;
     fHWDrawState.fStencilPass = kNone_StencilPass;
     fHWStencilClip = false;
+    fClipState.fClipIsDirty = true;
+    fClipState.fStencilClipTarget = NULL;
 
     fHWGeometryState.fIndexBuffer = NULL;
     fHWGeometryState.fVertexBuffer = NULL;
@@ -445,63 +436,6 @@
     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;
-        }
-        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) {
@@ -1202,19 +1136,12 @@
 
     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
+    GrAssert(NULL != fHWGeometryState.fIndexBuffer);
+    GrAssert(NULL != fHWGeometryState.fVertexBuffer);
+
+    // our setupGeometry better have adjusted this to zero since
+    // DrawElements always draws from the begining of the arrays for idx 0.
+    GrAssert(0 == startVertex);
 
     GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
                        GL_UNSIGNED_SHORT, indices));
@@ -1225,6 +1152,15 @@
                                    uint32_t vertexCount) {
     GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
 
+    GrAssert(NULL != fHWGeometryState.fVertexBuffer);
+
+    // our setupGeometry better have adjusted this to zero.
+    // DrawElements doesn't take an offset so we always adjus the startVertex.
+    GrAssert(0 == startVertex);
+
+    // pass 0 for parameter first. We have to adjust gl*Pointer() to
+    // account for startVertex in the DrawElements case. So we always
+    // rely on setupGeometry to have accounted for startVertex.
     GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
 }
 
@@ -1330,6 +1266,7 @@
                 if (!fCurrDrawState.fReverseFill) {
                     funcRef |= pathStencilMask;
                 }
+
                 GR_GL(StencilFunc(GL_EQUAL, funcRef, funcMask));
                 GR_GL(StencilMask(pathStencilMask));
                 GR_GL(StencilOp(GL_ZERO, GL_ZERO, GL_ZERO));
@@ -1425,6 +1362,7 @@
                 GLint  funcRef   = 0;
                 GLuint funcMask  = pathStencilMask;
                 GLenum funcFunc;
+
                 if (stencilClip) {
                     funcRef  |= clipStencilMask;
                     funcMask |= clipStencilMask;
@@ -1774,84 +1712,62 @@
     }
 }
 
+void GrGpuGL::setBuffers(bool indexed,
+                         int* extraVertexOffset,
+                         int* extraIndexOffset) {
 
-const GLvoid* GrGpuGL::setBuffersAndGetVertexStart(int vertexStride, int startVertex,
-                                                   int startIndex, int vertexCount,
-                                                   int indexCount) {
-    const GLvoid* posPtr = (GLvoid*)(vertexStride * startVertex);
+    GrAssert(NULL != extraVertexOffset);
 
-    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
+    GrGLVertexBuffer* vbuf;
+    switch (fGeometrySrc.fVertexSrc) {
+    case kBuffer_GeometrySrcType:
+        *extraVertexOffset = 0;
+        vbuf = (GrGLVertexBuffer*) fGeometrySrc.fVertexBuffer;
+        break;
+    case kArray_GeometrySrcType:
+    case kReserved_GeometrySrcType:
+        finalizeReservedVertices();
+        *extraVertexOffset = fCurrPoolStartVertex;
+        vbuf = (GrGLVertexBuffer*) fCurrPoolVertexBuffer;
+        break;
+    default:
+        vbuf = NULL; // suppress warning
+        GrCrash("Unknown geometry src type!");
     }
 
-    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
+    GrAssert(NULL != vbuf);
+    GrAssert(!vbuf->isLocked());
+    if (fHWGeometryState.fVertexBuffer != vbuf) {
+        GR_GL(BindBuffer(GL_ARRAY_BUFFER, vbuf->bufferID()));
+        fHWGeometryState.fArrayPtrsDirty = true;
+        fHWGeometryState.fVertexBuffer = vbuf;
     }
-    return posPtr;
+
+    if (indexed) {
+        GrAssert(NULL != extraIndexOffset);
+
+        GrGLIndexBuffer* ibuf;
+        switch (fGeometrySrc.fIndexSrc) {
+        case kBuffer_GeometrySrcType:
+            *extraIndexOffset = 0;
+            ibuf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
+            break;
+        case kArray_GeometrySrcType:
+        case kReserved_GeometrySrcType:
+            finalizeReservedIndices();
+            *extraIndexOffset = fCurrPoolStartIndex;
+            ibuf = (GrGLIndexBuffer*) fCurrPoolIndexBuffer;
+            break;
+        default:
+            ibuf = NULL; // suppress warning
+            GrCrash("Unknown geometry src type!");
+        }
+
+        GrAssert(NULL != ibuf);
+        GrAssert(!ibuf->isLocked());
+        if (fHWGeometryState.fIndexBuffer != ibuf) {
+            GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf->bufferID()));
+            fHWGeometryState.fIndexBuffer = ibuf;
+        }
+    }
 }
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index e46c2ce..d89b8d5 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -61,8 +61,7 @@
 
 protected:
     struct {
-        const void*
-        fPositionPtr;
+        size_t                  fVertexOffset;
         GrVertexLayout          fVertexLayout;
         const GrVertexBuffer*   fVertexBuffer;
         const GrIndexBuffer*    fIndexBuffer;
@@ -72,28 +71,27 @@
     DrState   fHWDrawState;
     bool      fHWStencilClip;
 
+    // GrGpu overrides
     virtual void drawIndexedHelper(PrimitiveType type,
                                    uint32_t startVertex,
                                    uint32_t startIndex,
                                    uint32_t vertexCount,
                                    uint32_t indexCount);
-
     virtual void drawNonIndexedHelper(PrimitiveType type,
                                       uint32_t vertexCount,
                                       uint32_t numVertices);
-
     virtual void flushScissor(const GrIRect* rect);
-
     void eraseStencil(uint32_t value, uint32_t mask);
     virtual void eraseStencilClip();
 
+    // binds texture unit in GL
     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);
+    // binds appropriate vertex and index buffers, also returns any extra
+    // extra verts or indices to offset by.
+    void setBuffers(bool indexed,
+                    int* extraVertexOffset,
+                    int* extraIndexOffset);
 
     // flushes state that is common to fixed and programmable GL
     // dither
@@ -118,13 +116,6 @@
 
     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();
 
@@ -174,13 +165,6 @@
     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 a028cba..76494de 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -95,7 +95,7 @@
     }
 
     fHWGeometryState.fVertexLayout = 0;
-    fHWGeometryState.fPositionPtr  = (void*) ~0;
+    fHWGeometryState.fVertexOffset  = ~0;
     GR_GL(EnableClientState(GL_VERTEX_ARRAY));
     GR_GL(DisableClientState(GL_TEXTURE_COORD_ARRAY));
     GR_GL(ShadeModel(GL_FLAT));
@@ -246,10 +246,10 @@
     return true;
 }
 
-void GrGpuGLFixed::setupGeometry(uint32_t startVertex,
-                                 uint32_t startIndex,
-                                 uint32_t vertexCount,
-                                 uint32_t indexCount) {
+void GrGpuGLFixed::setupGeometry(int* startVertex,
+                                 int* startIndex,
+                                 int vertexCount,
+                                 int indexCount) {
 
     int newColorOffset;
     int newTexCoordOffsets[kNumStages];
@@ -263,9 +263,11 @@
                                                     oldTexCoordOffsets,
                                                     &oldColorOffset);
 
-    const GLvoid* posPtr = setBuffersAndGetVertexStart(newStride, startVertex,
-                                                       startIndex, vertexCount,
-                                                       indexCount);
+    bool indexed = NULL == startIndex;
+
+    int extraVertexOffset;
+    int extraIndexOffset;
+    setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
 
     GLenum scalarType;
     if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
@@ -274,32 +276,43 @@
         scalarType = GrGLType;
     }
 
-    bool baseChange = posPtr != fHWGeometryState.fPositionPtr;
-    bool scalarChange =
-        (GrGLTextType != GrGLType) &&
-        (kTextFormat_VertexLayoutBit &
-         (fHWGeometryState.fVertexLayout ^ fGeometrySrc.fVertexLayout));
-    bool strideChange = newStride != oldStride;
-    bool posChange = baseChange || scalarChange || strideChange;
+    size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
+    *startVertex = 0;
+    if (indexed) {
+        *startIndex += extraIndexOffset;
+    }
 
-    if (posChange || fHWGeometryState.fArrayPtrsDirty) {
-        GR_GL(VertexPointer(2, scalarType, newStride, posPtr));
-        fHWGeometryState.fPositionPtr = posPtr;
+    // all the Pointers must be set if any of these are true
+    bool allOffsetsChange =  fHWGeometryState.fArrayPtrsDirty ||
+                             vertexOffset != fHWGeometryState.fVertexOffset ||
+                             newStride != oldStride;
+
+    // position and tex coord offsets change if above conditions are true
+    // or the type changed based on text vs nontext type coords.
+    bool posAndTexChange = allOffsetsChange ||
+                           ((GrGLTextType != GrGLType) &&
+                                (kTextFormat_VertexLayoutBit &
+                                  (fHWGeometryState.fVertexLayout ^
+                                   fGeometrySrc.fVertexLayout)));
+
+    if (posAndTexChange) {
+        GR_GL(VertexPointer(2, scalarType, newStride, (GLvoid*)vertexOffset));
+        fHWGeometryState.fVertexOffset = vertexOffset;
     }
 
     for (int s = 0; s < kNumStages; ++s) {
         // need to enable array if tex coord offset is 0
         // (using positions as coords)
         if (newTexCoordOffsets[s] >= 0) {
-            GLvoid* texCoordPtr = (int8_t*)posPtr + newTexCoordOffsets[s];
+            GLvoid* texCoordOffset = (GLvoid*)(vertexOffset + newTexCoordOffsets[s]);
             if (oldTexCoordOffsets[s] < 0) {
                 GR_GL(ClientActiveTexture(GL_TEXTURE0+s));
                 GR_GL(EnableClientState(GL_TEXTURE_COORD_ARRAY));
-                GR_GL(TexCoordPointer(2, scalarType, newStride, texCoordPtr));
-            } else if (fHWGeometryState.fArrayPtrsDirty || posChange ||
+                GR_GL(TexCoordPointer(2, scalarType, newStride, texCoordOffset));
+            } else if (posAndTexChange ||
                        newTexCoordOffsets[s] != oldTexCoordOffsets[s]) {
                 GR_GL(ClientActiveTexture(GL_TEXTURE0+s));
-                GR_GL(TexCoordPointer(2, scalarType, newStride, texCoordPtr));
+                GR_GL(TexCoordPointer(2, scalarType, newStride, texCoordOffset));
             }
         } else if (oldTexCoordOffsets[s] >= 0) {
             GR_GL(ClientActiveTexture(GL_TEXTURE0+s));
@@ -308,13 +321,12 @@
     }
 
     if (newColorOffset > 0) {
-        GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
+        GLvoid* colorOffset = (GLvoid*)(vertexOffset + newColorOffset);
         if (oldColorOffset <= 0) {
             GR_GL(EnableClientState(GL_COLOR_ARRAY));
-            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));
+            GR_GL(ColorPointer(4, GL_UNSIGNED_BYTE, newStride, colorOffset));
+        } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
+            GR_GL(ColorPointer(4, GL_UNSIGNED_BYTE, newStride, colorOffset));
         }
     } else if (oldColorOffset > 0) {
         GR_GL(DisableClientState(GL_COLOR_ARRAY));
diff --git a/gpu/src/GrGpuGLFixed.h b/gpu/src/GrGpuGLFixed.h
index 85db830..abb11aa 100644
--- a/gpu/src/GrGpuGLFixed.h
+++ b/gpu/src/GrGpuGLFixed.h
@@ -25,24 +25,24 @@
 public:
              GrGpuGLFixed();
     virtual ~GrGpuGLFixed();
-    
+
     virtual void resetContext();
 
 protected:
     // overrides from GrGpu
     virtual bool flushGraphicsState(PrimitiveType type);
-    virtual void setupGeometry(uint32_t startVertex,
-                               uint32_t startIndex,
-                               uint32_t vertexCount,
-                               uint32_t indexCount);
+    virtual void setupGeometry(int* startVertex,
+                               int* startIndex,
+                               int vertexCount,
+                               int indexCount);
 
 private:
     void resetContextHelper();
 
     // when the texture is GL_RGBA we set the GL_COMBINE texture
     // environment rgb operand 0 to be GL_COLOR to modulate each incoming
-    // R,G, & B by the texture's R, G, & B. When the texture is alpha-only we 
-    // set the operand to GL_ALPHA so that the incoming frag's R, G, &B are all 
+    // R,G, & B by the texture's R, G, & B. When the texture is alpha-only we
+    // set the operand to GL_ALPHA so that the incoming frag's R, G, &B are all
     // modulated by the texture's A.
     enum TextureEnvRGBOperands {
         kAlpha_TextureEnvRGBOperand,
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index b3bfc9a..cf41b1d 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -546,7 +546,7 @@
     fTextureOrientation = (GrGLTexture::Orientation)-1; // illegal
 
     fHWGeometryState.fVertexLayout = 0;
-    fHWGeometryState.fPositionPtr  = (void*) ~0;
+    fHWGeometryState.fVertexOffset = ~0;
     GR_GL(DisableVertexAttribArray(GR_GL_COL_ATTR_LOCATION));
     GR_GL(DisableVertexAttribArray(GR_GL_TEX_ATTR_LOCATION));
     GR_GL(EnableVertexAttribArray(GR_GL_POS_ATTR_LOCATION));
@@ -838,10 +838,10 @@
     return true;
 }
 
-void GrGpuGLShaders::setupGeometry(uint32_t startVertex,
-                                   uint32_t startIndex,
-                                   uint32_t vertexCount,
-                                   uint32_t indexCount) {
+void GrGpuGLShaders::setupGeometry(int* startVertex,
+                                   int* startIndex,
+                                   int vertexCount,
+                                   int indexCount) {
 
     int newColorOffset;
     int newTexCoordOffsets[kNumStages];
@@ -854,10 +854,11 @@
     GLsizei oldStride = VertexSizeAndOffsetsByStage(fHWGeometryState.fVertexLayout,
                                                     oldTexCoordOffsets,
                                                     &oldColorOffset);
+    bool indexed = NULL == startIndex;
 
-    const GLvoid* posPtr = setBuffersAndGetVertexStart(newStride, startVertex,
-                                                       startIndex, vertexCount,
-                                                       indexCount);
+    int extraVertexOffset;
+    int extraIndexOffset;
+    setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
 
     GLenum scalarType;
     bool texCoordNorm;
@@ -869,49 +870,58 @@
         texCoordNorm = false;
     }
 
-    bool baseChange = posPtr != fHWGeometryState.fPositionPtr;
-    bool scalarChange = (GrGLTextType != GrGLType) &&
-                        (kTextFormat_VertexLayoutBit &
-                         (fHWGeometryState.fVertexLayout ^
-                          fGeometrySrc.fVertexLayout));
-    bool strideChange = newStride != oldStride;
-    bool posChange = baseChange || scalarChange || strideChange;
+    size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
+    *startVertex = 0;
+    if (indexed) {
+        *startIndex += extraIndexOffset;
+    }
 
-    if (fHWGeometryState.fArrayPtrsDirty || posChange) {
+    // all the Pointers must be set if any of these are true
+    bool allOffsetsChange =  fHWGeometryState.fArrayPtrsDirty ||
+                             vertexOffset != fHWGeometryState.fVertexOffset ||
+                             newStride != oldStride;
+
+    // position and tex coord offsets change if above conditions are true
+    // or the type/normalization changed based on text vs nontext type coords.
+    bool posAndTexChange = allOffsetsChange ||
+                           (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
+                                (kTextFormat_VertexLayoutBit &
+                                  (fHWGeometryState.fVertexLayout ^
+                                   fGeometrySrc.fVertexLayout)));
+
+    if (posAndTexChange) {
         GR_GL(VertexAttribPointer(GR_GL_POS_ATTR_LOCATION, 2, scalarType,
-                                  false, newStride, posPtr));
-        fHWGeometryState.fPositionPtr = posPtr;
+                                  false, newStride, (GLvoid*)vertexOffset));
+        fHWGeometryState.fVertexOffset = vertexOffset;
     }
 
     // this class only supports one stage.
     if (newTexCoordOffsets[0] > 0) {
-        GLvoid* texCoordPtr = (int8_t*)posPtr + newTexCoordOffsets[0];
+        GLvoid* texCoordOffset = (GLvoid*)(vertexOffset + newTexCoordOffsets[0]);
         if (oldTexCoordOffsets[0] <= 0) {
             GR_GL(EnableVertexAttribArray(GR_GL_TEX_ATTR_LOCATION));
             GR_GL(VertexAttribPointer(GR_GL_TEX_ATTR_LOCATION, 2, scalarType,
-                                      texCoordNorm, newStride, texCoordPtr));
-        } else if (fHWGeometryState.fArrayPtrsDirty || posChange ||
-            newTexCoordOffsets[0] != oldTexCoordOffsets[0]) {
+                                      texCoordNorm, newStride, texCoordOffset));
+        } else if (posAndTexChange ||
+                   newTexCoordOffsets[0] != oldTexCoordOffsets[0]) {
             GR_GL(VertexAttribPointer(GR_GL_TEX_ATTR_LOCATION, 2, scalarType,
-                                      texCoordNorm, newStride, texCoordPtr));
+                                      texCoordNorm, newStride, texCoordOffset));
         }
     } else if (oldTexCoordOffsets[0] > 0) {
         GR_GL(DisableVertexAttribArray(GR_GL_TEX_ATTR_LOCATION));
     }
 
     if (newColorOffset > 0) {
-        GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
+        GLvoid* colorOffset = (GLvoid*)(vertexOffset + 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 (fHWGeometryState.fArrayPtrsDirty || posChange ||
-            newColorOffset != oldColorOffset) {
+                                      true, newStride, colorOffset));
+        } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
             GR_GL(VertexAttribPointer(GR_GL_COL_ATTR_LOCATION, 4,
                                       GL_UNSIGNED_BYTE,
-                                      true, newStride, colorPtr));
+                                      true, newStride, colorOffset));
         }
     } else if (oldColorOffset > 0) {
         GR_GL(DisableVertexAttribArray(GR_GL_COL_ATTR_LOCATION));
diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h
index e5a5665..a048e93 100644
--- a/gpu/src/GrGpuGLShaders.h
+++ b/gpu/src/GrGpuGLShaders.h
@@ -25,7 +25,7 @@
 public:
              GrGpuGLShaders();
     virtual ~GrGpuGLShaders();
-    
+
     virtual void resetContext();
 
     // type of colors used by a program
@@ -37,27 +37,27 @@
 protected:
     // overrides from GrGpu
     virtual bool flushGraphicsState(PrimitiveType type);
-    virtual void setupGeometry(uint32_t startVertex,
-                               uint32_t startIndex,
-                               uint32_t vertexCount,
-                               uint32_t indexCount);
-    
+    virtual void setupGeometry(int* startVertex,
+                               int* startIndex,
+                               int vertexCount,
+                               int indexCount);
+
 private:
     void resetContextHelper();
-    
+
     // sets the texture matrix uniform for currently bound program
-    void flushTexMatrix(GLint location, 
+    void flushTexMatrix(GLint location,
                         GrGLTexture::Orientation orientation);
     // sets the MVP matrix uniform for currently bound program
     void flushMatrix(GLint location);
-    
+
     void flushTwoPointRadial(GLint paramsLocation, const GrSamplerState&);
-    
+
     // reads shader from array and compiles it with GL, returns shader ID or 0 if failed
     GLuint loadShader(GLenum type, const char* src);
-    
+
     struct ProgramData;
-    // creates a GL program with two shaders attached. 
+    // creates a GL program with two shaders attached.
     // Gets the relevant uniform locations.
     // Sets the texture sampler if present to texture 0
     // Binds the program
@@ -74,17 +74,17 @@
     void flushProgram(PrimitiveType type);
 
     enum Programs {
-        // use vertex coordinates         
+        // use vertex coordinates
         kTextureVertCoords_Program = 0,
         kTextureVertCoordsProj_Program,
-        
+
         // use separate tex coords
         kTextureTexCoords_Program,
         kTextureTexCoordsProj_Program,
 
         // constant color texture, no proj
         // verts as a tex coords
-        kTextureVertCoordsNoColor_Program,        
+        kTextureVertCoordsNoColor_Program,
 
         // constant color texture, no proj
         // separate tex coords
@@ -99,12 +99,12 @@
 
         // programs for sweep texture lookup
         kSweepTextureVertCoords_Program,
-        kSweepTextureTexCoords_Program, 
-        
+        kSweepTextureTexCoords_Program,
+
         // programs for two-point radial lookup
         kTwoPointRadialTextureVertCoords_Program,
         kTwoPointRadialTextureTexCoords_Program,
-        
+
         // color only drawing
         kNoTexture_Program,
 
@@ -113,23 +113,23 @@
 
     // Records per-program information
     // we can specify the attribute locations so that they are constant
-    // across our shaders. But the driver determines the uniform locations 
+    // across our shaders. But the driver determines the uniform locations
     // at link time. We don't need to remember the sampler uniform location
     // because we will bind a texture slot to it and never change it
-    // Uniforms are program-local so we can't rely on fHWState to hold the 
+    // Uniforms are program-local so we can't rely on fHWState to hold the
     // previous uniform state after a program change.
     struct ProgramData {
         // IDs
         GLuint    fVShaderID;
         GLuint    fFShaderID;
         GLuint    fProgramID;
-        
+
         // shader uniform locations (-1 if shader doesn't use them)
         GLint     fMatrixLocation;
         GLint     fTexMatrixLocation;
         GLint     fColorLocation;
         GLint     fTwoPointParamsLocation;
-        
+
         ColorType fColorType;
 
         // these reflect the current values of uniforms
@@ -142,10 +142,10 @@
         GrScalar                    fRadial2Radius0;
         bool                        fRadial2PosRoot;
     };
-    
+
     ProgramData fPrograms[kProgramCount];
     Programs    fHWProgram;
-    
+
     GrGLTexture::Orientation  fTextureOrientation;
 
     typedef GrGpuGL INHERITED;
diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp
index 81f83c9..d423ee2 100644
--- a/gpu/src/GrGpuGLShaders2.cpp
+++ b/gpu/src/GrGpuGLShaders2.cpp
@@ -983,7 +983,7 @@
 
     // Must initialize all fields or cache will have false negatives!
     desc->fVertexLayout = fGeometrySrc.fVertexLayout;
-    
+
     desc->fOptFlags = 0;
     if (kPoints_PrimitiveType != primType) {
         desc->fOptFlags |= ProgramDesc::kNotPoints_OptFlagBit;
@@ -1112,7 +1112,7 @@
     fTextureOrientation = (GrGLTexture::Orientation)-1; // illegal
 
     fHWGeometryState.fVertexLayout = 0;
-    fHWGeometryState.fPositionPtr  = (void*) ~0;
+    fHWGeometryState.fVertexOffset  = ~0;
     GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
     for (int t = 0; t < kMaxTexCoords; ++t) {
         GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
@@ -1315,10 +1315,10 @@
     return true;
 }
 
-void GrGpuGLShaders2::setupGeometry(uint32_t startVertex,
-                                    uint32_t startIndex,
-                                    uint32_t vertexCount,
-                                    uint32_t indexCount) {
+void GrGpuGLShaders2::setupGeometry(int* startVertex,
+                                    int* startIndex,
+                                    int vertexCount,
+                                    int indexCount) {
 
     int newColorOffset;
     int newTexCoordOffsets[kMaxTexCoords];
@@ -1331,10 +1331,11 @@
     GLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
                                                   oldTexCoordOffsets,
                                                   &oldColorOffset);
+    bool indexed = NULL != startIndex;
 
-    const GLvoid* posPtr = setBuffersAndGetVertexStart(newStride, startVertex, 
-                                                       startIndex, vertexCount,
-                                                       indexCount);
+    int extraVertexOffset;
+    int extraIndexOffset;
+    setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
 
     GLenum scalarType;
     bool texCoordNorm;
@@ -1346,31 +1347,42 @@
         texCoordNorm = false;
     }
 
-    bool baseChange = posPtr != fHWGeometryState.fPositionPtr;
-    bool scalarChange = (GrGLTextType != GrGLType) &&
-                        (kTextFormat_VertexLayoutBit &
-                         (fHWGeometryState.fVertexLayout ^
-                          fGeometrySrc.fVertexLayout));
-    bool strideChange = newStride != oldStride;
-    bool posChange = baseChange || scalarChange || strideChange;
+    size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
+    *startVertex = 0;
+    if (indexed) {
+        *startIndex += extraIndexOffset;
+    }
 
-    if (fHWGeometryState.fArrayPtrsDirty || posChange) {
+    // all the Pointers must be set if any of these are true
+    bool allOffsetsChange =  fHWGeometryState.fArrayPtrsDirty ||
+                             vertexOffset != fHWGeometryState.fVertexOffset ||
+                             newStride != oldStride;
+
+    // position and tex coord offsets change if above conditions are true
+    // or the type/normalization changed based on text vs nontext type coords.
+    bool posAndTexChange = allOffsetsChange ||
+                           (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
+                                (kTextFormat_VertexLayoutBit &
+                                  (fHWGeometryState.fVertexLayout ^
+                                   fGeometrySrc.fVertexLayout)));
+
+    if (posAndTexChange) {
         GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
-                                  false, newStride, posPtr));
-        fHWGeometryState.fPositionPtr = posPtr;
+                                  false, newStride, (GLvoid*)vertexOffset));
+        fHWGeometryState.fVertexOffset = vertexOffset;
     }
 
     for (int t = 0; t < kMaxTexCoords; ++t) {
         if (newTexCoordOffsets[t] > 0) {
-            GLvoid* texCoordPtr = (int8_t*)posPtr + newTexCoordOffsets[t];
+            GLvoid* texCoordOffset = (GLvoid*)(vertexOffset + newTexCoordOffsets[t]);
             if (oldTexCoordOffsets[t] <= 0) {
                 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
                 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
-                                          texCoordNorm, newStride, texCoordPtr));
-            } else if (fHWGeometryState.fArrayPtrsDirty || posChange || 
-                newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
+                                          texCoordNorm, newStride, texCoordOffset));
+            } else if (posAndTexChange ||
+                       newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
                 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
-                                          texCoordNorm, newStride, texCoordPtr));
+                                          texCoordNorm, newStride, texCoordOffset));
             }
         } else if (oldTexCoordOffsets[t] > 0) {
             GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
@@ -1378,23 +1390,23 @@
     }
 
     if (newColorOffset > 0) {
-        GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
+        GLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
         if (oldColorOffset <= 0) {
             GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
             GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
                                       GL_UNSIGNED_BYTE,
-                                      true, newStride, colorPtr));
-        } else if (fHWGeometryState.fArrayPtrsDirty || posChange || 
-            newColorOffset != oldColorOffset) {
+                                      true, newStride, colorOffset));
+        } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
             GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
                                       GL_UNSIGNED_BYTE,
-                                      true, newStride, colorPtr));
+                                      true, newStride, colorOffset));
         }
     } else if (oldColorOffset > 0) {
         GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
     }
 
     fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
+    fHWGeometryState.fArrayPtrsDirty = false;
 }
 #endif
 
diff --git a/gpu/src/GrGpuGLShaders2.h b/gpu/src/GrGpuGLShaders2.h
index bba63f6..bb710e3 100644
--- a/gpu/src/GrGpuGLShaders2.h
+++ b/gpu/src/GrGpuGLShaders2.h
@@ -31,10 +31,10 @@
 protected:
     // overrides from GrGpu
     virtual bool flushGraphicsState(PrimitiveType type);
-    virtual void setupGeometry(uint32_t startVertex,
-                               uint32_t startIndex,
-                               uint32_t vertexCount,
-                               uint32_t indexCount);
+    virtual void setupGeometry(int* startVertex,
+                               int* startIndex,
+                               int vertexCount,
+                               int indexCount);
 
 private:
 
@@ -42,7 +42,7 @@
 
     // sets the texture matrix uniform for currently bound program
     void flushTextureMatrix(int stage);
-   
+
     // sets the MVP matrix uniform for currently bound program
     void flushViewMatrix();
 
diff --git a/gpu/src/GrInOrderDrawBuffer.cpp b/gpu/src/GrInOrderDrawBuffer.cpp
index 494f227..49b8901 100644
--- a/gpu/src/GrInOrderDrawBuffer.cpp
+++ b/gpu/src/GrInOrderDrawBuffer.cpp
@@ -17,25 +17,27 @@
 
 #include "GrInOrderDrawBuffer.h"
 #include "GrTexture.h"
-#include "GrVertexBufferAllocPool.h"
+#include "GrBufferAllocPool.h"
 #include "GrGpu.h"
 
-GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrVertexBufferAllocPool* pool) :
+GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrVertexBufferAllocPool* vertexPool,
+                                         GrIndexBufferAllocPool* indexPool) :
         fDraws(DRAWS_BLOCK_SIZE, fDrawsStorage),
         fStates(STATES_BLOCK_SIZE, fStatesStorage),
         fClips(CLIPS_BLOCK_SIZE, fClipsStorage),
         fClipChanged(true),
-        fCPUVertices((NULL == pool) ? 0 : VERTEX_BLOCK_SIZE),
-        fBufferVertices(pool),
-        fIndices(INDEX_BLOCK_SIZE),
-        fCurrReservedVertices(NULL),
-        fCurrReservedIndices(NULL),
-        fCurrVertexBuffer(NULL),
+        fVertexPool(*vertexPool),
+        fCurrPoolVertexBuffer(NULL),
+        fCurrPoolStartVertex(0),
+        fIndexPool(*indexPool),
+        fCurrPoolIndexBuffer(NULL),
+        fCurrPoolStartIndex(0),
         fReservedVertexBytes(0),
         fReservedIndexBytes(0),
         fUsedReservedVertexBytes(0),
         fUsedReservedIndexBytes(0) {
-    GrAssert(NULL == pool || pool->getGpu()->supportsBufferLocking());
+    GrAssert(NULL != vertexPool);
+    GrAssert(NULL != indexPool);
 }
 
 GrInOrderDrawBuffer::~GrInOrderDrawBuffer() {
@@ -47,108 +49,95 @@
     this->setClip(target.getClip());
 }
 
-void GrInOrderDrawBuffer::drawIndexed(PrimitiveType type,
-                                      uint32_t startVertex,
-                                      uint32_t startIndex,
-                                      uint32_t vertexCount,
-                                      uint32_t indexCount) {
+void GrInOrderDrawBuffer::drawIndexed(PrimitiveType primitiveType,
+                                      int startVertex,
+                                      int startIndex,
+                                      int vertexCount,
+                                      int indexCount) {
 
     if (!vertexCount || !indexCount) {
         return;
     }
 
     Draw& draw = fDraws.push_back();
-    draw.fType          = type;
+    draw.fPrimitiveType = primitiveType;
     draw.fStartVertex   = startVertex;
     draw.fStartIndex    = startIndex;
     draw.fVertexCount   = vertexCount;
     draw.fIndexCount    = indexCount;
     draw.fClipChanged   = grabClip();
-    draw.fStateChange   = grabState();
+    draw.fStateChanged  = grabState();
 
     draw.fVertexLayout = fGeometrySrc.fVertexLayout;
     switch (fGeometrySrc.fVertexSrc) {
-    case kArray_GeometrySrcType:
-        draw.fUseVertexBuffer = false;
-        draw.fVertexArray = fGeometrySrc.fVertexArray;
-        break;
-    case kReserved_GeometrySrcType: {
-        draw.fUseVertexBuffer = NULL != fBufferVertices;
-        if (draw.fUseVertexBuffer) {
-            draw.fVertexBuffer = fCurrVertexBuffer;
-            draw.fStartVertex += fCurrStartVertex;
-        } else {
-            draw.fVertexArray = fCurrReservedVertices;
-        }
-        size_t vertexBytes = (vertexCount + startVertex) *
-                             VertexSize(fGeometrySrc.fVertexLayout);
-        fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes,
-                                         vertexBytes);
-        } break;
     case kBuffer_GeometrySrcType:
-        draw.fUseVertexBuffer = true;
         draw.fVertexBuffer = fGeometrySrc.fVertexBuffer;
         break;
+    case kReserved_GeometrySrcType: {
+        size_t vertexBytes = (vertexCount + startVertex) *
+        VertexSize(fGeometrySrc.fVertexLayout);
+        fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes,
+                                         vertexBytes);
+    } // fallthrough
+    case kArray_GeometrySrcType:
+        draw.fVertexBuffer = fCurrPoolVertexBuffer;
+        draw.fStartVertex += fCurrPoolStartVertex;
+        break;
+    default:
+        GrCrash("unknown geom src type");
     }
 
     switch (fGeometrySrc.fIndexSrc) {
-    case kArray_GeometrySrcType:
-        draw.fUseIndexBuffer = false;
-        draw.fIndexArray = fGeometrySrc.fIndexArray;
-        break;
-    case kReserved_GeometrySrcType: {
-        draw.fUseIndexBuffer = false;
-        draw.fIndexArray = fCurrReservedIndices;
-        size_t indexBytes = (indexCount + startIndex) * sizeof(uint16_t);
-        fUsedReservedIndexBytes = GrMax(fUsedReservedIndexBytes, indexBytes);
-        } break;
     case kBuffer_GeometrySrcType:
-        draw.fUseIndexBuffer = true;
         draw.fIndexBuffer = fGeometrySrc.fIndexBuffer;
         break;
+    case kReserved_GeometrySrcType: {
+        size_t indexBytes = (indexCount + startIndex) * sizeof(uint16_t);
+        fUsedReservedIndexBytes = GrMax(fUsedReservedIndexBytes, indexBytes);
+    } // fallthrough
+    case kArray_GeometrySrcType:
+        draw.fIndexBuffer = fCurrPoolIndexBuffer;
+        draw.fStartIndex += fCurrPoolStartVertex;
+        break;
+    default:
+        GrCrash("unknown geom src type");
     }
 }
 
-void GrInOrderDrawBuffer::drawNonIndexed(PrimitiveType type,
-                                         uint32_t startVertex,
-                                         uint32_t vertexCount) {
+void GrInOrderDrawBuffer::drawNonIndexed(PrimitiveType primitiveType,
+                                         int startVertex,
+                                         int vertexCount) {
     if (!vertexCount) {
         return;
     }
 
     Draw& draw = fDraws.push_back();
-    draw.fType          = type;
+    draw.fPrimitiveType = primitiveType;
     draw.fStartVertex   = startVertex;
     draw.fStartIndex    = 0;
     draw.fVertexCount   = vertexCount;
     draw.fIndexCount    = 0;
 
     draw.fClipChanged   = grabClip();
-    draw.fStateChange   = grabState();
+    draw.fStateChanged  = grabState();
 
     draw.fVertexLayout = fGeometrySrc.fVertexLayout;
     switch (fGeometrySrc.fVertexSrc) {
-    case kArray_GeometrySrcType:
-        draw.fUseVertexBuffer = false;
-        draw.fVertexArray = fGeometrySrc.fVertexArray;
-        break;
-    case kReserved_GeometrySrcType: {
-        draw.fUseVertexBuffer = NULL != fBufferVertices;
-        if (draw.fUseVertexBuffer) {
-            draw.fVertexBuffer = fCurrVertexBuffer;
-            draw.fStartVertex += fCurrStartVertex;
-        } else {
-            draw.fVertexArray = fCurrReservedVertices;
-        }
-        size_t vertexBytes = (vertexCount + startVertex) *
-                             VertexSize(fGeometrySrc.fVertexLayout);
-        fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes,
-                                         vertexBytes);
-        } break;
     case kBuffer_GeometrySrcType:
-        draw.fUseVertexBuffer = true;
         draw.fVertexBuffer = fGeometrySrc.fVertexBuffer;
         break;
+    case kReserved_GeometrySrcType: {
+        size_t vertexBytes = (vertexCount + startVertex) *
+        VertexSize(fGeometrySrc.fVertexLayout);
+        fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes,
+                                         vertexBytes);
+    } // fallthrough
+    case kArray_GeometrySrcType:
+        draw.fVertexBuffer = fCurrPoolVertexBuffer;
+        draw.fStartVertex += fCurrPoolStartVertex;
+        break;
+    default:
+        GrCrash("unknown geom src type");
     }
 }
 
@@ -165,12 +154,10 @@
     }
     fDraws.reset();
     fStates.reset();
-    if (NULL == fBufferVertices) {
-        fCPUVertices.reset();
-    } else {
-        fBufferVertices->reset();
-    }
-    fIndices.reset();
+
+    fVertexPool.reset();
+    fIndexPool.reset();
+
     fClips.reset();
 }
 
@@ -183,9 +170,8 @@
         return;
     }
 
-    if (NULL != fBufferVertices) {
-        fBufferVertices->unlock();
-    }
+    fVertexPool.unlock();
+    fIndexPool.unlock();
 
     GrDrawTarget::AutoStateRestore asr(target);
     GrDrawTarget::AutoClipRestore acr(target);
@@ -198,7 +184,7 @@
 
     for (uint32_t i = 0; i < numDraws; ++i) {
         const Draw& draw = fDraws[i];
-        if (draw.fStateChange) {
+        if (draw.fStateChanged) {
             ++currState;
             target->restoreDrawState(fStates[currState]);
         }
@@ -206,52 +192,58 @@
             ++currClip;
             target->setClip(fClips[currClip]);
         }
-        if (draw.fUseVertexBuffer) {
-            target->setVertexSourceToBuffer(draw.fVertexBuffer, draw.fVertexLayout);
-        } else {
-            target->setVertexSourceToArray(draw.fVertexArray, draw.fVertexLayout);
-        }
+        uint32_t vertexReserveCount = 0;
+        uint32_t indexReserveCount = 0;
+
+        target->setVertexSourceToBuffer(draw.fVertexLayout, draw.fVertexBuffer);
+
         if (draw.fIndexCount) {
-            if (draw.fUseIndexBuffer) {
-                target->setIndexSourceToBuffer(draw.fIndexBuffer);
-            } else {
-                target->setIndexSourceToArray(draw.fIndexArray);
-            }
-            target->drawIndexed(draw.fType,
+            target->setIndexSourceToBuffer(draw.fIndexBuffer);
+        }
+
+        if (draw.fIndexCount) {
+            target->drawIndexed(draw.fPrimitiveType,
                                 draw.fStartVertex,
                                 draw.fStartIndex,
                                 draw.fVertexCount,
                                 draw.fIndexCount);
         } else {
-            target->drawNonIndexed(draw.fType,
+            target->drawNonIndexed(draw.fPrimitiveType,
                                    draw.fStartVertex,
                                    draw.fVertexCount);
         }
+        if (vertexReserveCount || indexReserveCount) {
+            target->releaseReservedGeometry();
+        }
     }
 }
 
 bool GrInOrderDrawBuffer::geometryHints(GrVertexLayout vertexLayout,
-                                        int32_t* vertexCount,
-                                        int32_t* indexCount) const {
+                                        int* vertexCount,
+                                        int* indexCount) const {
+    // we will recommend a flush if the data could fit in a single
+    // preallocated buffer but none are left and it can't fit
+    // in the current buffer (which may not be prealloced).
     bool flush = false;
     if (NULL != indexCount) {
-        *indexCount  = -1;
+        int32_t currIndices = fIndexPool.currentBufferIndices();
+        if (*indexCount > currIndices &&
+            (!fIndexPool.preallocatedBuffersRemaining() &&
+             *indexCount <= fIndexPool.preallocatedBufferIndices())) {
+
+            flush = true;
+        }
+        *indexCount = currIndices;
     }
     if (NULL != vertexCount) {
-        if (NULL != fBufferVertices) {
-            // we will recommend a flush if the verts could fit in a single
-            // preallocated vertex buffer but none are left and it can't fit
-            // in the current VB (which may not be prealloced).
-            if (*vertexCount > fBufferVertices->currentBufferVertices(vertexLayout) &&
-                (!fBufferVertices->preallocatedBuffersRemaining() &&
-                 *vertexCount <= fBufferVertices->preallocatedBufferVertices(vertexLayout))) {
+        int32_t currVertices = fVertexPool.currentBufferVertices(vertexLayout);
+        if (*vertexCount > currVertices &&
+            (!fVertexPool.preallocatedBuffersRemaining() &&
+             *vertexCount <= fVertexPool.preallocatedBufferVertices(vertexLayout))) {
 
-                flush = true;
-            }
-            *vertexCount = fBufferVertices->currentBufferVertices(vertexLayout);
-        } else {
-            *vertexCount = -1;
+            flush = true;
         }
+        *vertexCount = currVertices;
     }
     return flush;
 }
@@ -259,31 +251,34 @@
 bool GrInOrderDrawBuffer::acquireGeometryHelper(GrVertexLayout vertexLayout,
                                                 void**         vertices,
                                                 void**         indices) {
+    GrAssert(!fReservedGeometry.fLocked);
     if (fReservedGeometry.fVertexCount) {
+        GrAssert(NULL != vertices);
+        GrAssert(0 == fReservedVertexBytes);
+        GrAssert(0 == fUsedReservedVertexBytes);
+
         fReservedVertexBytes = VertexSize(vertexLayout) *
                                fReservedGeometry.fVertexCount;
-        if (NULL == fBufferVertices) {
-            fCurrReservedVertices = fCPUVertices.alloc(fReservedVertexBytes);
-        } else {
-            fCurrReservedVertices = fBufferVertices->alloc(vertexLayout,
-                                                           fReservedGeometry.fVertexCount,
-                                                           &fCurrVertexBuffer,
-                                                           &fCurrStartVertex);
-        }
-        if (NULL != vertices) {
-            *vertices = fCurrReservedVertices;
-        }
-        if (NULL == fCurrReservedVertices) {
+        *vertices = fVertexPool.makeSpace(vertexLayout,
+                                          fReservedGeometry.fVertexCount,
+                                          &fCurrPoolVertexBuffer,
+                                          &fCurrPoolStartVertex);
+        if (NULL == *vertices) {
             return false;
         }
     }
     if (fReservedGeometry.fIndexCount) {
-        fReservedIndexBytes = sizeof(uint16_t) * fReservedGeometry.fIndexCount;
-        fCurrReservedIndices = fIndices.alloc(fReservedIndexBytes);
-        if (NULL != indices) {
-            *indices = fCurrReservedIndices;
-        }
-        if (NULL == fCurrReservedIndices) {
+        GrAssert(NULL != indices);
+        GrAssert(0 == fReservedIndexBytes);
+        GrAssert(0 == fUsedReservedIndexBytes);
+
+        *indices = fIndexPool.makeSpace(fReservedGeometry.fIndexCount,
+                                        &fCurrPoolIndexBuffer,
+                                        &fCurrPoolStartIndex);
+        if (NULL == *indices) {
+            fVertexPool.putBack(fReservedVertexBytes);
+            fReservedVertexBytes = 0;
+            fCurrPoolVertexBuffer = NULL;
             return false;
         }
     }
@@ -295,22 +290,45 @@
     GrAssert(fUsedReservedIndexBytes <= fReservedIndexBytes);
 
     size_t vertexSlack = fReservedVertexBytes - fUsedReservedVertexBytes;
-    if (NULL == fBufferVertices) {
-        fCPUVertices.release(vertexSlack);
-    } else {
-        fBufferVertices->release(vertexSlack);
-        GR_DEBUGCODE(fCurrVertexBuffer = NULL);
-        GR_DEBUGCODE(fCurrStartVertex  = 0);
-    }
+    fVertexPool.putBack(vertexSlack);
 
-    fIndices.release(fReservedIndexBytes - fUsedReservedIndexBytes);
+    size_t indexSlack = fReservedIndexBytes - fUsedReservedIndexBytes;
+    fIndexPool.putBack(indexSlack);
 
-    fCurrReservedVertices = NULL;
-    fCurrReservedIndices  = NULL;
     fReservedVertexBytes = 0;
     fReservedIndexBytes  = 0;
     fUsedReservedVertexBytes = 0;
     fUsedReservedIndexBytes  = 0;
+    fCurrPoolVertexBuffer = 0;
+    fCurrPoolStartVertex = 0;
+
+}
+
+void GrInOrderDrawBuffer::setVertexSourceToArrayHelper(const void* vertexArray,
+                                                       int vertexCount) {
+    GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
+#if GR_DEBUG
+    bool success =
+#endif
+    fVertexPool.appendVertices(fGeometrySrc.fVertexLayout,
+                               vertexCount,
+                               vertexArray,
+                               &fCurrPoolVertexBuffer,
+                               &fCurrPoolStartVertex);
+    GR_DEBUGASSERT(success);
+}
+
+void GrInOrderDrawBuffer::setIndexSourceToArrayHelper(const void* indexArray,
+                                                      int indexCount) {
+    GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
+#if GR_DEBUG
+    bool success =
+#endif
+    fIndexPool.appendIndices(indexCount,
+                             indexArray,
+                             &fCurrPoolIndexBuffer,
+                             &fCurrPoolStartIndex);
+    GR_DEBUGASSERT(success);
 }
 
 bool GrInOrderDrawBuffer::grabState() {
diff --git a/gpu/src/GrVertexBufferAllocPool.cpp b/gpu/src/GrVertexBufferAllocPool.cpp
deleted file mode 100644
index 360a086..0000000
--- a/gpu/src/GrVertexBufferAllocPool.cpp
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
-    Copyright 2010 Google Inc.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
- */
-
-
-#include "GrVertexBufferAllocPool.h"
-#include "GrVertexBuffer.h"
-#include "GrGpu.h"
-
-#define GrVertexBufferAllocPool_MIN_BLOCK_SIZE      ((size_t)1 << 10)
-
-GrVertexBufferAllocPool::GrVertexBufferAllocPool(GrGpu* gpu,
-                                                 size_t blockSize,
-                                                 int preallocBufferCnt) :
-        fBlocks(GrMax(8, 2*preallocBufferCnt)) {
-    GrAssert(NULL != gpu);
-    fGpu = gpu;
-    fGpu->ref();
-    fBufferPtr = NULL;
-    fMinBlockSize = GrMax(GrVertexBufferAllocPool_MIN_BLOCK_SIZE, blockSize);
-
-    fPreallocBuffersInUse = 0;
-    fFirstPreallocBuffer = 0;
-    for (int i = 0; i < preallocBufferCnt; ++i) {
-        GrVertexBuffer* buffer = gpu->createVertexBuffer(fMinBlockSize, true);
-        if (NULL != buffer) {
-            *fPreallocBuffers.append() = buffer;
-            buffer->ref();
-        }
-    }
-}
-
-GrVertexBufferAllocPool::~GrVertexBufferAllocPool() {
-    fPreallocBuffers.unrefAll();
-    while (!fBlocks.empty()) {
-        destroyBlock();
-    }
-    fGpu->unref();
-}
-
-void GrVertexBufferAllocPool::reset() {
-    while (!fBlocks.empty()) {
-        destroyBlock();
-    }
-    if (fPreallocBuffers.count()) {
-        // must set this after above loop.
-        fFirstPreallocBuffer = (fFirstPreallocBuffer + fPreallocBuffersInUse) %
-                               fPreallocBuffers.count();
-    }
-    GrAssert(0 == fPreallocBuffersInUse);
-}
-
-void GrVertexBufferAllocPool::unlock() {
-    GrAssert((NULL == fBufferPtr) ? (!fBlocks.empty() ||
-                                     !fBlocks.back().fVertexBuffer->isLocked()) :
-                                    (!fBlocks.empty() &&
-                                     fBlocks.back().fVertexBuffer->isLocked()));
-    if (NULL != fBufferPtr) {
-        GrAssert(!fBlocks.empty());
-        GrAssert(fBlocks.back().fVertexBuffer->isLocked());
-        fBufferPtr = NULL;
-        fBlocks.back().fVertexBuffer->unlock();
-    }
-#if GR_DEBUG
-    for (uint32_t i = 0; i < fBlocks.count(); ++i) {
-        GrAssert(!fBlocks[i].fVertexBuffer->isLocked());
-    }
-#endif
-}
-
-void* GrVertexBufferAllocPool::alloc(GrVertexLayout layout,
-                                     uint32_t vertexCount,
-                                     GrVertexBuffer** buffer,
-                                     uint32_t* startVertex) {
-    GrAssert(NULL != buffer);
-    size_t vSize = GrDrawTarget::VertexSize(layout);
-    size_t bytes = vSize * vertexCount;
-
-    if (NULL != fBufferPtr) {
-        GrAssert(!fBlocks.empty());
-        GrAssert(fBlocks.back().fVertexBuffer->isLocked());
-        BufferBlock& back = fBlocks.back();
-        uint32_t usedBytes = back.fVertexBuffer->size() - back.fBytesFree;
-        uint32_t pad = GrUIAlignUpPad(usedBytes, 
-                                      GrDrawTarget::VertexSize(layout));
-        if ((bytes + pad) <= back.fBytesFree) {
-            usedBytes += pad;
-            *startVertex = usedBytes / vSize;
-            *buffer = back.fVertexBuffer;
-            back.fBytesFree -= bytes + pad;
-            return (void*)((intptr_t)fBufferPtr + usedBytes);
-        }
-    }
-
-    if (!createBlock(GrMax(bytes, fMinBlockSize))) {
-        return NULL;
-    }
-    *startVertex = 0;
-    GrAssert(NULL != fBufferPtr);
-    BufferBlock& back = fBlocks.back();
-    *buffer = back.fVertexBuffer;
-    back.fBytesFree -= bytes;
-    return fBufferPtr;
-}
-
-int GrVertexBufferAllocPool::currentBufferVertices(GrVertexLayout layout) const {
-    if (NULL != fBufferPtr) {
-        GrAssert(!fBlocks.empty());
-        const BufferBlock& back = fBlocks.back();
-        GrAssert(back.fVertexBuffer->isLocked());
-        return back.fBytesFree / GrDrawTarget::VertexSize(layout);
-    } else if (fPreallocBuffersInUse < fPreallocBuffers.count()) {
-        return fMinBlockSize / GrDrawTarget::VertexSize(layout);
-    }
-    return 0;
-}
-
-int GrVertexBufferAllocPool::preallocatedBuffersRemaining() const {
-    return fPreallocBuffers.count() - fPreallocBuffersInUse;
-}
-
-int GrVertexBufferAllocPool::preallocatedBufferVertices(GrVertexLayout layout) const {
-    return fPreallocBuffers.count() ?
-                        (fMinBlockSize / GrDrawTarget::VertexSize(layout)) :
-                        0;
-}
-
-int GrVertexBufferAllocPool::preallocatedBufferCount() const {
-    return fPreallocBuffers.count();
-}
-
-void GrVertexBufferAllocPool::release(size_t bytes) {
-    if (NULL != fBufferPtr) {
-        GrAssert(!fBlocks.empty());
-        BufferBlock& back = fBlocks.back();
-        GrAssert(back.fVertexBuffer->isLocked());
-        size_t bytesUsed = back.fVertexBuffer->size() - back.fBytesFree;
-        if (bytes >= bytesUsed) {
-            destroyBlock();
-            bytes -= bytesUsed;
-        } else {
-            back.fBytesFree += bytes;
-            return;
-        }
-    }
-    GrAssert(NULL == fBufferPtr);
-    GrAssert(fBlocks.empty() ||
-             !fBlocks.back().fVertexBuffer->isLocked());
-    // we don't honor release if it is within an already unlocked VB
-    // Our VB semantics say locking a VB discards its previous content
-    while (!fBlocks.empty() &&
-           bytes >= fBlocks.back().fVertexBuffer->size()) {
-        bytes -= fBlocks.back().fVertexBuffer->size();
-        destroyBlock();
-    }
-}
-
-bool GrVertexBufferAllocPool::createBlock(size_t size) {
-    GrAssert(size >= GrVertexBufferAllocPool_MIN_BLOCK_SIZE);
-
-    BufferBlock& block = fBlocks.push_back();
-
-    if (size == fMinBlockSize &&
-        fPreallocBuffersInUse < fPreallocBuffers.count()) {
-
-        uint32_t nextBuffer = (fPreallocBuffersInUse + fFirstPreallocBuffer) %
-                              fPreallocBuffers.count();
-        block.fVertexBuffer = fPreallocBuffers[nextBuffer];
-        block.fVertexBuffer->ref();
-        ++fPreallocBuffersInUse;
-    } else {
-        block.fVertexBuffer = fGpu->createVertexBuffer(size, true);
-        if (NULL == block.fVertexBuffer) {
-            fBlocks.pop_back();
-            return false;
-        }
-    }
-
-    block.fBytesFree = size;
-    if (NULL != fBufferPtr) {
-        GrAssert(fBlocks.count() > 1);
-        BufferBlock& prev = fBlocks.fromBack(1);
-        GrAssert(prev.fVertexBuffer->isLocked());
-        fBufferPtr = NULL;
-        prev.fVertexBuffer->unlock();
-    }
-    fBufferPtr = block.fVertexBuffer->lock();
-    return true;
-}
-
-void GrVertexBufferAllocPool::destroyBlock() {
-    GrAssert(!fBlocks.empty());
-
-    BufferBlock& block = fBlocks.back();
-    if (fPreallocBuffersInUse > 0) {
-        uint32_t prevPreallocBuffer = (fPreallocBuffersInUse +
-                                       fFirstPreallocBuffer +
-                                       (fPreallocBuffers.count() - 1)) %
-                                      fPreallocBuffers.count();
-        if (block.fVertexBuffer == fPreallocBuffers[prevPreallocBuffer]) {
-            --fPreallocBuffersInUse;
-        }
-    }
-    block.fVertexBuffer->unref();
-    fBlocks.pop_back();
-    fBufferPtr = NULL;
-}
-
-
diff --git a/gpu/src/gr_files.mk b/gpu/src/gr_files.mk
index 67d2838..4c06345 100644
--- a/gpu/src/gr_files.mk
+++ b/gpu/src/gr_files.mk
@@ -22,4 +22,4 @@
     GrTextureCache.cpp \
     GrTextContext.cpp \
     GrTextStrike.cpp \
-    GrVertexBufferAllocPool.cpp
+    GrBufferAllocPool.cpp