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/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