Refactor GrDrawTarget vertex/index api
Review URL: http://codereview.appspot.com/4631056/



git-svn-id: http://skia.googlecode.com/svn/trunk@1662 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrBufferAllocPool.cpp b/gpu/src/GrBufferAllocPool.cpp
index d786b02..73d707f 100644
--- a/gpu/src/GrBufferAllocPool.cpp
+++ b/gpu/src/GrBufferAllocPool.cpp
@@ -23,9 +23,10 @@
 #if GR_DEBUG
     #define VALIDATE validate
 #else
-    #define VALIDATE()
+    static void VALIDATE(bool x = false) {}
 #endif
 
+// page size
 #define GrBufferAllocPool_MIN_BLOCK_SIZE ((size_t)1 << 12)
 
 GrBufferAllocPool::GrBufferAllocPool(GrGpu* gpu,
@@ -45,6 +46,8 @@
     fBufferPtr = NULL;
     fMinBlockSize = GrMax(GrBufferAllocPool_MIN_BLOCK_SIZE, blockSize);
 
+    fBytesInUse = 0;
+            
     fPreallocBuffersInUse = 0;
     fFirstPreallocBuffer = 0;
     for (int i = 0; i < preallocBufferCnt; ++i) {
@@ -80,6 +83,7 @@
 
 void GrBufferAllocPool::reset() {
     VALIDATE();
+    fBytesInUse = 0;
     if (fBlocks.count()) {
         GrGeometryBuffer* buffer = fBlocks.back().fBuffer;
         if (buffer->isLocked()) {
@@ -116,7 +120,7 @@
 }
 
 #if GR_DEBUG
-void GrBufferAllocPool::validate() const {
+void GrBufferAllocPool::validate(bool unusedBlockAllowed) const {
     if (NULL != fBufferPtr) {
         GrAssert(!fBlocks.empty());
         if (fBlocks.back().fBuffer->isLocked()) {
@@ -129,9 +133,23 @@
     } else {
         GrAssert(fBlocks.empty() || !fBlocks.back().fBuffer->isLocked());
     }
+    size_t bytesInUse = 0;
     for (int i = 0; i < fBlocks.count() - 1; ++i) {
         GrAssert(!fBlocks[i].fBuffer->isLocked());
     }
+    for (int i = 0; i < fBlocks.count(); ++i) {
+        size_t bytes = fBlocks[i].fBuffer->size() - fBlocks[i].fBytesFree; 
+        bytesInUse += bytes;
+        GrAssert(bytes || unusedBlockAllowed);
+    }
+    
+    GrAssert(bytesInUse == fBytesInUse);
+    if (unusedBlockAllowed) {
+        GrAssert((fBytesInUse && !fBlocks.empty()) ||
+                 (!fBytesInUse && (fBlocks.count() < 2)));
+    } else {
+        GrAssert((0 == fBytesInUse) == fBlocks.empty());
+    }
 }
 #endif
 
@@ -154,20 +172,27 @@
             *offset = usedBytes;
             *buffer = back.fBuffer;
             back.fBytesFree -= size + pad;
+            fBytesInUse += size;
             return (void*)(reinterpret_cast<intptr_t>(fBufferPtr) + usedBytes);
         }
     }
 
+    // We could honor the space request using updateSubData on the current VB
+    // (if there is room). But we don't currently use draw calls to GL that
+    // allow the driver to know that previously issued draws won't read from
+    // the part of the buffer we update.
+    
     if (!createBlock(size)) {
         return NULL;
     }
-    VALIDATE();
     GrAssert(NULL != fBufferPtr);
 
     *offset = 0;
     BufferBlock& back = fBlocks.back();
     *buffer = back.fBuffer;
     back.fBytesFree -= size;
+    fBytesInUse += size;
+    VALIDATE();
     return fBufferPtr;
 }
 
@@ -194,29 +219,24 @@
 
 void GrBufferAllocPool::putBack(size_t bytes) {
     VALIDATE();
-    if (NULL != fBufferPtr) {
-        BufferBlock& back = fBlocks.back();
-        size_t bytesUsed = back.fBuffer->size() - back.fBytesFree;
+
+    while (bytes) {
+        // caller shouldnt try to put back more than they've taken
+        GrAssert(!fBlocks.empty());
+        BufferBlock& block = fBlocks.back();
+        size_t bytesUsed = block.fBuffer->size() - block.fBytesFree;
         if (bytes >= bytesUsed) {
-            destroyBlock();
             bytes -= bytesUsed;
+            fBytesInUse -= bytesUsed;
+            destroyBlock();
         } else {
-            back.fBytesFree += bytes;
-            return;
+            block.fBytesFree += bytes;
+            fBytesInUse -= bytes;
+            bytes = 0;
+            break;
         }
     }
     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) {
@@ -269,7 +289,7 @@
         fBufferPtr = fCpuData.realloc(size);
     }
 
-    VALIDATE();
+    VALIDATE(true);
 
     return true;
 }
diff --git a/gpu/src/GrBufferAllocPool.h b/gpu/src/GrBufferAllocPool.h
index 7d70ebb..c18e36b 100644
--- a/gpu/src/GrBufferAllocPool.h
+++ b/gpu/src/GrBufferAllocPool.h
@@ -169,8 +169,10 @@
     void destroyBlock();
     void flushCpuData(GrGeometryBuffer* buffer, size_t flushSize);
 #if GR_DEBUG
-    void validate() const;
+    void validate(bool unusedBlockAllowed = false) const;
 #endif
+    
+    size_t                          fBytesInUse;
 
     GrGpu*                          fGpu;
     bool                            fGpuIsReffed;
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index b5f9259..cc64058 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -18,6 +18,8 @@
 #include "GrDrawTarget.h"
 #include "GrGpuVertex.h"
 #include "GrTexture.h"
+#include "GrVertexBuffer.h"
+#include "GrIndexBuffer.h"
 
 namespace {
 
@@ -282,17 +284,33 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-GrDrawTarget::GrDrawTarget() {
+#define DEBUG_INVAL_BUFFER 0xdeadcafe
+#define DEBUG_INVAL_START_IDX -1
+
+GrDrawTarget::GrDrawTarget() 
+: fGeoSrcStateStack(&fGeoSrcStateStackStorage) {
 #if GR_DEBUG
     VertexLayoutUnitTest();
 #endif
-    fReservedGeometry.fLocked = false;
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.push_back();
 #if GR_DEBUG
-    fReservedGeometry.fVertexCount  = ~0;
-    fReservedGeometry.fIndexCount   = ~0;
+    geoSrc.fVertexCount = DEBUG_INVAL_START_IDX;
+    geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
+    geoSrc.fIndexCount = DEBUG_INVAL_START_IDX;
+    geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
 #endif
-    fGeometrySrc.fVertexSrc = kReserved_GeometrySrcType;
-    fGeometrySrc.fIndexSrc  = kReserved_GeometrySrcType;
+    geoSrc.fVertexSrc = kNone_GeometrySrcType;
+    geoSrc.fIndexSrc  = kNone_GeometrySrcType;
+}
+
+GrDrawTarget::~GrDrawTarget() {
+    int popCnt = fGeoSrcStateStack.count() - 1;
+    while (popCnt) {
+        this->popGeometrySource();
+        --popCnt;
+    }
+    this->releasePreviousVertexSource();
+    this->releasePreviousIndexSource();
 }
 
 void GrDrawTarget::setClip(const GrClip& clip) {
@@ -429,39 +447,54 @@
     fCurrDrawState = srcTarget.fCurrDrawState;
 }
 
+bool GrDrawTarget::reserveVertexSpace(GrVertexLayout vertexLayout,
+                                      int vertexCount,
+                                      void** vertices) {
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    bool acquired = false;
+    if (vertexCount > 0) {
+        GrAssert(NULL != vertices);
+        this->releasePreviousVertexSource();
+        geoSrc.fVertexSrc = kNone_GeometrySrcType;
 
-bool GrDrawTarget::reserveAndLockGeometry(GrVertexLayout    vertexLayout,
-                                          uint32_t          vertexCount,
-                                          uint32_t          indexCount,
-                                          void**            vertices,
-                                          void**            indices) {
-    GrAssert(!fReservedGeometry.fLocked);
-    fReservedGeometry.fVertexCount  = vertexCount;
-    fReservedGeometry.fIndexCount   = indexCount;
-
-    fReservedGeometry.fLocked = this->onAcquireGeometry(vertexLayout,
-                                                        vertices,
-                                                        indices);
-    if (fReservedGeometry.fLocked) {
-        if (vertexCount) {
-            fGeometrySrc.fVertexSrc = kReserved_GeometrySrcType;
-            fGeometrySrc.fVertexLayout = vertexLayout;
-        } else if (NULL != vertices) {
-            *vertices = NULL;
-        }
-        if (indexCount) {
-            fGeometrySrc.fIndexSrc = kReserved_GeometrySrcType;
-        } else if (NULL != indices) {
-            *indices = NULL;
-        }
+        acquired = this->onReserveVertexSpace(vertexLayout,
+                                              vertexCount,
+                                              vertices);
     }
-    return fReservedGeometry.fLocked;
+    if (acquired) {
+        geoSrc.fVertexSrc = kReserved_GeometrySrcType;
+        geoSrc.fVertexCount = vertexCount;
+        geoSrc.fVertexLayout = vertexLayout;
+    } else if (NULL != vertices) {
+        *vertices = NULL;
+    }
+    return acquired;
+}
+
+bool GrDrawTarget::reserveIndexSpace(int indexCount,
+                                     void** indices) {
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    bool acquired = false;
+    if (indexCount > 0) {
+        GrAssert(NULL != indices);
+        this->releasePreviousIndexSource();
+        geoSrc.fIndexSrc = kNone_GeometrySrcType;
+        
+        acquired = this->onReserveIndexSpace(indexCount, indices);
+    }
+    if (acquired) {
+        geoSrc.fIndexSrc = kReserved_GeometrySrcType;
+        geoSrc.fIndexCount = indexCount;
+    } else if (NULL != indices) {
+        *indices = NULL;
+    }
+    return acquired;
+    
 }
 
 bool GrDrawTarget::geometryHints(GrVertexLayout vertexLayout,
                                  int32_t* vertexCount,
                                  int32_t* indexCount) const {
-    GrAssert(!fReservedGeometry.fLocked);
     if (NULL != vertexCount) {
         *vertexCount = -1;
     }
@@ -471,39 +504,199 @@
     return false;
 }
 
-void GrDrawTarget::releaseReservedGeometry() {
-    GrAssert(fReservedGeometry.fLocked);
-    this->onReleaseGeometry();
-    fReservedGeometry.fLocked = false;
+void GrDrawTarget::releasePreviousVertexSource() {
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    switch (geoSrc.fVertexSrc) {
+        case kNone_GeometrySrcType:
+            break;
+        case kArray_GeometrySrcType:
+            this->releaseVertexArray();
+            break;
+        case kReserved_GeometrySrcType:
+            this->releaseReservedVertexSpace();
+            break;
+        case kBuffer_GeometrySrcType:
+            geoSrc.fVertexBuffer->unref();
+#if GR_DEBUG
+            geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
+#endif
+            break;
+        default:
+            GrCrash("Unknown Vertex Source Type.");
+            break;
+    }
+}
+
+void GrDrawTarget::releasePreviousIndexSource() {
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    switch (geoSrc.fIndexSrc) {
+        case kNone_GeometrySrcType:   // these two don't require
+            break;
+        case kArray_GeometrySrcType:
+            this->releaseIndexArray();
+            break;
+        case kReserved_GeometrySrcType:
+            this->releaseReservedIndexSpace();
+            break;
+        case kBuffer_GeometrySrcType:
+            geoSrc.fIndexBuffer->unref();
+#if GR_DEBUG
+            geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
+#endif
+            break;
+        default:
+            GrCrash("Unknown Index Source Type.");
+            break;
+    }
 }
 
 void GrDrawTarget::setVertexSourceToArray(GrVertexLayout vertexLayout,
                                           const void* vertexArray,
                                           int vertexCount) {
-    fGeometrySrc.fVertexSrc = kArray_GeometrySrcType;
-    fGeometrySrc.fVertexLayout = vertexLayout;
+    this->releasePreviousVertexSource();
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    geoSrc.fVertexSrc = kArray_GeometrySrcType;
+    geoSrc.fVertexLayout = vertexLayout;
+    geoSrc.fVertexCount = vertexCount;
     this->onSetVertexSourceToArray(vertexArray, vertexCount);
 }
 
 void GrDrawTarget::setIndexSourceToArray(const void* indexArray,
                                          int indexCount) {
-    fGeometrySrc.fIndexSrc = kArray_GeometrySrcType;
+    this->releasePreviousIndexSource();
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    geoSrc.fIndexSrc = kArray_GeometrySrcType;
+    geoSrc.fIndexCount = indexCount;
     this->onSetIndexSourceToArray(indexArray, indexCount);
 }
 
 void GrDrawTarget::setVertexSourceToBuffer(GrVertexLayout vertexLayout,
                                            const GrVertexBuffer* buffer) {
-    fGeometrySrc.fVertexSrc    = kBuffer_GeometrySrcType;
-    fGeometrySrc.fVertexBuffer = buffer;
-    fGeometrySrc.fVertexLayout = vertexLayout;
+    this->releasePreviousVertexSource();
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    geoSrc.fVertexSrc    = kBuffer_GeometrySrcType;
+    geoSrc.fVertexBuffer = buffer;
+    buffer->ref();
+    geoSrc.fVertexLayout = vertexLayout;
 }
 
 void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) {
-    fGeometrySrc.fIndexSrc     = kBuffer_GeometrySrcType;
-    fGeometrySrc.fIndexBuffer  = buffer;
+    this->releasePreviousIndexSource();
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    geoSrc.fIndexSrc     = kBuffer_GeometrySrcType;
+    geoSrc.fIndexBuffer  = buffer;
+    buffer->ref();
 }
 
-///////////////////////////////////////////////////////////////////////////////
+void GrDrawTarget::resetVertexSource() {
+    this->releasePreviousVertexSource();
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    geoSrc.fVertexSrc = kNone_GeometrySrcType;
+}
+
+void GrDrawTarget::resetIndexSource() {
+    this->releasePreviousIndexSource();
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    geoSrc.fIndexSrc = kNone_GeometrySrcType;
+}
+
+void GrDrawTarget::pushGeometrySource() {
+    this->geometrySourceWillPush();
+    GeometrySrcState& newState = fGeoSrcStateStack.push_back();
+    newState.fIndexSrc = kNone_GeometrySrcType;
+    newState.fVertexSrc = kNone_GeometrySrcType;
+#if GR_DEBUG
+    newState.fVertexCount  = ~0;
+    newState.fVertexBuffer = (GrVertexBuffer*)~0;
+    newState.fIndexCount   = ~0;
+    newState.fIndexBuffer = (GrIndexBuffer*)~0;
+#endif
+}
+
+void GrDrawTarget::popGeometrySource() {
+    const GeometrySrcState& geoSrc = this->getGeomSrc();
+    // if popping last element then pops are unbalanced with pushes
+    GrAssert(fGeoSrcStateStack.count() > 1);
+    
+    this->geometrySourceWillPop(fGeoSrcStateStack.fromBack(1));
+    this->releasePreviousVertexSource();
+    this->releasePreviousIndexSource();
+    fGeoSrcStateStack.pop_back();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDrawTarget::drawIndexed(GrPrimitiveType type, int startVertex,
+                               int startIndex, int vertexCount,
+                               int indexCount) {
+#if GR_DEBUG
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    int maxVertex = startVertex + vertexCount;
+    int maxValidVertex;
+    switch (geoSrc.fVertexSrc) {
+        case kNone_GeometrySrcType:
+            GrCrash("Attempting to draw indexed geom without vertex src.");
+        case kReserved_GeometrySrcType: // fallthrough
+        case kArray_GeometrySrcType:
+            maxValidVertex = geoSrc.fVertexCount;
+            break;
+        case kBuffer_GeometrySrcType:
+            maxValidVertex = geoSrc.fVertexBuffer->size() / 
+                             VertexSize(geoSrc.fVertexLayout);
+            break;
+    }
+    if (maxVertex > maxValidVertex) {
+        GrCrash("Indexed drawing outside valid vertex range.");
+    }
+    int maxIndex = startIndex + indexCount;
+    int maxValidIndex;
+    switch (geoSrc.fIndexSrc) {
+        case kNone_GeometrySrcType:
+            GrCrash("Attempting to draw indexed geom without index src.");
+        case kReserved_GeometrySrcType: // fallthrough
+        case kArray_GeometrySrcType:
+            maxValidIndex = geoSrc.fIndexCount;
+            break;
+        case kBuffer_GeometrySrcType:
+            maxValidIndex = geoSrc.fIndexBuffer->size() / sizeof(uint16_t);
+            break;
+    }
+    if (maxIndex > maxValidIndex) {
+        GrCrash("Indexed drawing outside valid index range.");
+    }
+#endif
+    this->onDrawIndexed(type, startVertex, startIndex,
+                        vertexCount, indexCount);
+}
+
+
+void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
+                                  int startVertex,
+                                  int vertexCount) {
+#if GR_DEBUG
+    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+    int maxVertex = startVertex + vertexCount;
+    int maxValidVertex;
+    switch (geoSrc.fVertexSrc) {
+        case kNone_GeometrySrcType:
+            GrCrash("Attempting to draw non-indexed geom without vertex src.");
+        case kReserved_GeometrySrcType: // fallthrough
+        case kArray_GeometrySrcType:
+            maxValidVertex = geoSrc.fVertexCount;
+            break;
+        case kBuffer_GeometrySrcType:
+            maxValidVertex = geoSrc.fVertexBuffer->size() / 
+            VertexSize(geoSrc.fVertexLayout);
+            break;
+    }
+    if (maxVertex > maxValidVertex) {
+        GrCrash("Non-indexed drawing outside valid vertex range.");
+    }
+#endif
+    this->onDrawNonIndexed(type, startVertex, vertexCount);
+}
+
+////////////////////////////////////////////////////////////////////////////////
 
 bool GrDrawTarget::canDisableBlend() const {
     // If we compute a coverage value (using edge AA or a coverage stage) then
@@ -523,7 +716,7 @@
     }
 
     // If we have vertex color without alpha then we can't force blend off
-    if ((fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) ||
+    if ((this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) ||
          0xff != GrColorUnpackA(fCurrDrawState.fColor)) {
         return false;
     }
@@ -572,7 +765,8 @@
 }
 
 
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
 void GrDrawTarget::drawRect(const GrRect& rect, 
                             const GrMatrix* matrix,
                             StageBitfield stageEnableBitfield,
@@ -648,7 +842,7 @@
     }
 }
 
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
 GrDrawTarget::AutoStateRestore::AutoStateRestore() {
     fDrawTarget = NULL;
@@ -679,7 +873,7 @@
     }
 }
 
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
 GrDrawTarget::AutoDeviceCoordDraw::AutoDeviceCoordDraw(GrDrawTarget* target, 
                                                        int stageMask) {
@@ -714,3 +908,62 @@
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry(
+                                         GrDrawTarget*  target,
+                                         GrVertexLayout vertexLayout,
+                                         int vertexCount,
+                                         int indexCount) {
+    fTarget = NULL;
+    this->set(target, vertexLayout, vertexCount, indexCount);
+}
+    
+GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry() {
+    fTarget = NULL;
+}
+
+GrDrawTarget::AutoReleaseGeometry::~AutoReleaseGeometry() {
+    this->reset();
+}
+
+bool GrDrawTarget::AutoReleaseGeometry::set(GrDrawTarget*  target,
+                                            GrVertexLayout vertexLayout,
+                                            int vertexCount,
+                                            int indexCount) {
+    this->reset();
+    fTarget = target;
+    bool success = true;
+    if (NULL != fTarget) {
+        fTarget = target;
+        if (vertexCount > 0) {
+            success = target->reserveVertexSpace(vertexLayout, 
+                                                 vertexCount,
+                                                 &fVertices);
+            if (!success) {
+                this->reset();
+            }
+        }
+        if (success && indexCount > 0) {
+            success = target->reserveIndexSpace(indexCount, &fIndices);
+            if (!success) {
+                this->reset();
+            }
+        }
+    }
+    GrAssert(success == (NULL != fTarget));
+    return success;
+}
+
+void GrDrawTarget::AutoReleaseGeometry::reset() {
+    if (NULL != fTarget) {
+        if (NULL != fVertices) {
+            fTarget->resetVertexSource();
+        }
+        if (NULL != fIndices) {
+            fTarget->resetIndexSource();
+        }
+        fTarget = NULL;
+    }
+}
+
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index 4f260c7..db7de2c 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -33,27 +33,36 @@
 
 extern void gr_run_unittests();
 
+#define DEBUG_INVAL_BUFFER    0xdeadcafe
+#define DEBUG_INVAL_START_IDX -1
+
 GrGpu::GrGpu()
     : f8bitPaletteSupport(false)
-    , fCurrPoolVertexBuffer(NULL)
-    , fCurrPoolStartVertex(0)
-    , fCurrPoolIndexBuffer(NULL)
-    , fCurrPoolStartIndex(0)
     , fContext(NULL)
     , fVertexPool(NULL)
     , fIndexPool(NULL)
+    , fVertexPoolUseCnt(0)
+    , fIndexPoolUseCnt(0)
+    , fGeomPoolStateStack(&fGeoSrcStateStackStorage)
     , fQuadIndexBuffer(NULL)
     , fUnitSquareVertexBuffer(NULL)
     , fDefaultPathRenderer(NULL)
     , fClientPathRenderer(NULL)
     , fContextIsDirty(true)
-    , fVertexPoolInUse(false)
-    , fIndexPoolInUse(false)
     , fResourceHead(NULL) {
 
 #if GR_DEBUG
     //gr_run_unittests();
 #endif
+        
+    fGeomPoolStateStack.push_back();
+#if GR_DEBUG
+    GeometryPoolState& poolState = fGeomPoolStateStack.back();
+    poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
+    poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
+    poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
+    poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
+#endif
     resetStats();
 }
 
@@ -417,7 +426,7 @@
             fClip.setFromRect(bounds);
 
             AutoStateRestore asr(this);
-            AutoInternalDrawGeomRestore aidgr(this);
+            AutoGeometryPush agp(this);
 
             this->setViewMatrix(GrMatrix::I());
             this->clearStencilClip(clipRect);
@@ -566,15 +575,36 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrGpu::drawIndexed(GrPrimitiveType type,
-                        int startVertex,
-                        int startIndex,
-                        int vertexCount,
-                        int indexCount) {
-    GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
-             fReservedGeometry.fLocked);
-    GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
-             fReservedGeometry.fLocked);
+void GrGpu::geometrySourceWillPush() {
+    const GeometrySrcState& geoSrc = this->getGeomSrc();
+    if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
+        kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
+        this->finalizeReservedVertices();
+    }
+    if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
+        kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
+        this->finalizeReservedIndices();
+    }
+    GeometryPoolState& newState = fGeomPoolStateStack.push_back();
+#if GR_DEBUG
+    newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
+    newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
+    newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
+    newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
+#endif
+}
+
+void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
+    // if popping last entry then pops are unbalanced with pushes
+    GrAssert(fGeomPoolStateStack.count() > 1);
+    fGeomPoolStateStack.pop_back();
+}
+
+void GrGpu::onDrawIndexed(GrPrimitiveType type,
+                          int startVertex,
+                          int startIndex,
+                          int vertexCount,
+                          int indexCount) {
 
     this->handleDirtyContext();
 
@@ -592,16 +622,13 @@
     int sIndex = startIndex;
     setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
 
-    this->onDrawIndexed(type, sVertex, sIndex,
-                        vertexCount, indexCount);
+    this->onGpuDrawIndexed(type, sVertex, sIndex,
+                           vertexCount, indexCount);
 }
 
-void GrGpu::drawNonIndexed(GrPrimitiveType type,
+void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
                            int startVertex,
                            int vertexCount) {
-    GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
-             fReservedGeometry.fLocked);
-
     this->handleDirtyContext();
 
     if (!this->setupClipAndFlushState(type)) {
@@ -615,7 +642,7 @@
     int sVertex = startVertex;
     setupGeometry(&sVertex, NULL, vertexCount, 0);
 
-    this->onDrawNonIndexed(type, sVertex, vertexCount);
+    this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
 }
 
 void GrGpu::finalizeReservedVertices() {
@@ -630,11 +657,12 @@
 
 void GrGpu::prepareVertexPool() {
     if (NULL == fVertexPool) {
+        GrAssert(0 == fVertexPoolUseCnt);
         fVertexPool = new GrVertexBufferAllocPool(this, true,
                                                   VERTEX_POOL_VB_SIZE,
                                                   VERTEX_POOL_VB_COUNT);
         fVertexPool->releaseGpuRef();
-    } else if (!fVertexPoolInUse) {
+    } else if (!fVertexPoolUseCnt) {
         // the client doesn't have valid data in the pool
         fVertexPool->reset();
     }
@@ -642,81 +670,117 @@
 
 void GrGpu::prepareIndexPool() {
     if (NULL == fIndexPool) {
+        GrAssert(0 == fIndexPoolUseCnt);
         fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
         fIndexPool->releaseGpuRef();
-    } else if (!fIndexPoolInUse) {
+    } else if (!fIndexPoolUseCnt) {
         // the client doesn't have valid data in the pool
         fIndexPool->reset();
     }
 }
 
-bool GrGpu::onAcquireGeometry(GrVertexLayout vertexLayout,
-                              void**         vertices,
-                              void**         indices) {
-    GrAssert(!fReservedGeometry.fLocked);
-    size_t reservedVertexSpace = 0;
-
-    if (fReservedGeometry.fVertexCount) {
-        GrAssert(NULL != vertices);
-
-        this->prepareVertexPool();
-
-        *vertices = fVertexPool->makeSpace(vertexLayout,
-                                           fReservedGeometry.fVertexCount,
-                                           &fCurrPoolVertexBuffer,
-                                           &fCurrPoolStartVertex);
-        if (NULL == *vertices) {
-            return false;
-        }
-        reservedVertexSpace = VertexSize(vertexLayout) *
-                              fReservedGeometry.fVertexCount;
+bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
+                                 int vertexCount,
+                                 void** vertices) {
+    GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
+    
+    GrAssert(vertexCount > 0);
+    GrAssert(NULL != vertices);
+    
+    this->prepareVertexPool();
+    
+    *vertices = fVertexPool->makeSpace(vertexLayout,
+                                       vertexCount,
+                                       &geomPoolState.fPoolVertexBuffer,
+                                       &geomPoolState.fPoolStartVertex);
+    if (NULL == *vertices) {
+        return false;
     }
-    if (fReservedGeometry.fIndexCount) {
-        GrAssert(NULL != indices);
-
-        this->prepareIndexPool();
-
-        *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
-                                         &fCurrPoolIndexBuffer,
-                                         &fCurrPoolStartIndex);
-        if (NULL == *indices) {
-            fVertexPool->putBack(reservedVertexSpace);
-            fCurrPoolVertexBuffer = NULL;
-            return false;
-        }
-    }
+    ++fVertexPoolUseCnt;
     return true;
 }
 
-void GrGpu::onReleaseGeometry() {}
+bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
+    GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
+    
+    GrAssert(indexCount > 0);
+    GrAssert(NULL != indices);
+
+    this->prepareIndexPool();
+
+    *indices = fIndexPool->makeSpace(indexCount,
+                                     &geomPoolState.fPoolIndexBuffer,
+                                     &geomPoolState.fPoolStartIndex);
+    if (NULL == *indices) {
+        return false;
+    }
+    ++fIndexPoolUseCnt;
+    return true;
+}
+
+void GrGpu::releaseReservedVertexSpace() {
+    const GeometrySrcState& geoSrc = this->getGeomSrc();
+    GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
+    size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
+    fVertexPool->putBack(bytes);
+    --fVertexPoolUseCnt;
+}
+
+void GrGpu::releaseReservedIndexSpace() {
+    const GeometrySrcState& geoSrc = this->getGeomSrc();
+    GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
+    size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
+    fIndexPool->putBack(bytes);
+    --fIndexPoolUseCnt;
+}
 
 void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
-    GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
     this->prepareVertexPool();
+    GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
 #if GR_DEBUG
     bool success =
 #endif
-    fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
+    fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
                                 vertexCount,
                                 vertexArray,
-                                &fCurrPoolVertexBuffer,
-                                &fCurrPoolStartVertex);
+                                &geomPoolState.fPoolVertexBuffer,
+                                &geomPoolState.fPoolStartVertex);
+    ++fVertexPoolUseCnt;
     GR_DEBUGASSERT(success);
 }
 
 void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
-    GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
     this->prepareIndexPool();
+    GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
 #if GR_DEBUG
     bool success =
 #endif
     fIndexPool->appendIndices(indexCount,
                               indexArray,
-                              &fCurrPoolIndexBuffer,
-                              &fCurrPoolStartIndex);
+                              &geomPoolState.fPoolIndexBuffer,
+                              &geomPoolState.fPoolStartIndex);
+    ++fIndexPoolUseCnt;
     GR_DEBUGASSERT(success);
 }
 
+void GrGpu::releaseVertexArray() {
+    // if vertex source was array, we stowed data in the pool
+    const GeometrySrcState& geoSrc = this->getGeomSrc();
+    GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
+    size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
+    fVertexPool->putBack(bytes);
+    --fVertexPoolUseCnt;
+}
+
+void GrGpu::releaseIndexArray() {
+    // if index source was array, we stowed data in the pool
+    const GeometrySrcState& geoSrc = this->getGeomSrc();
+    GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
+    size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
+    fIndexPool->putBack(bytes);
+    --fIndexPoolUseCnt;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 const GrGpuStats& GrGpu::getStats() const {
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index c73f60f..ffdf496 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -1401,11 +1401,11 @@
     #endif
 #endif
 
-void GrGpuGL::onDrawIndexed(GrPrimitiveType type,
-                            uint32_t startVertex,
-                            uint32_t startIndex,
-                            uint32_t vertexCount,
-                            uint32_t indexCount) {
+void GrGpuGL::onGpuDrawIndexed(GrPrimitiveType type,
+                               uint32_t startVertex,
+                               uint32_t startIndex,
+                               uint32_t vertexCount,
+                               uint32_t indexCount) {
     GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
 
     GrGLvoid* indices = (GrGLvoid*)(sizeof(uint16_t) * startIndex);
@@ -1433,9 +1433,9 @@
 #endif
 }
 
-void GrGpuGL::onDrawNonIndexed(GrPrimitiveType type,
-                               uint32_t startVertex,
-                               uint32_t vertexCount) {
+void GrGpuGL::onGpuDrawNonIndexed(GrPrimitiveType type,
+                                  uint32_t startVertex,
+                                  uint32_t vertexCount) {
     GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
 
     GrAssert(NULL != fHWGeometryState.fVertexBuffer);
@@ -1924,7 +1924,7 @@
 }
 
 void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
-    fGeometrySrc.fIndexBuffer = buffer;
+    fHWGeometryState.fIndexBuffer = buffer;
 }
 
 void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
@@ -2058,17 +2058,19 @@
 
     GrAssert(NULL != extraVertexOffset);
 
+    const GeometryPoolState& geoPoolState = this->getGeomPoolState();
+
     GrGLVertexBuffer* vbuf;
-    switch (fGeometrySrc.fVertexSrc) {
+    switch (this->getGeomSrc().fVertexSrc) {
     case kBuffer_GeometrySrcType:
         *extraVertexOffset = 0;
-        vbuf = (GrGLVertexBuffer*) fGeometrySrc.fVertexBuffer;
+        vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer;
         break;
     case kArray_GeometrySrcType:
     case kReserved_GeometrySrcType:
-        finalizeReservedVertices();
-        *extraVertexOffset = fCurrPoolStartVertex;
-        vbuf = (GrGLVertexBuffer*) fCurrPoolVertexBuffer;
+        this->finalizeReservedVertices();
+        *extraVertexOffset = geoPoolState.fPoolStartVertex;
+        vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer;
         break;
     default:
         vbuf = NULL; // suppress warning
@@ -2087,16 +2089,16 @@
         GrAssert(NULL != extraIndexOffset);
 
         GrGLIndexBuffer* ibuf;
-        switch (fGeometrySrc.fIndexSrc) {
+        switch (this->getGeomSrc().fIndexSrc) {
         case kBuffer_GeometrySrcType:
             *extraIndexOffset = 0;
-            ibuf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
+            ibuf = (GrGLIndexBuffer*)this->getGeomSrc().fIndexBuffer;
             break;
         case kArray_GeometrySrcType:
         case kReserved_GeometrySrcType:
-            finalizeReservedIndices();
-            *extraIndexOffset = fCurrPoolStartIndex;
-            ibuf = (GrGLIndexBuffer*) fCurrPoolIndexBuffer;
+            this->finalizeReservedIndices();
+            *extraIndexOffset = geoPoolState.fPoolStartIndex;
+            ibuf = (GrGLIndexBuffer*) geoPoolState.fPoolIndexBuffer;
             break;
         default:
             ibuf = NULL; // suppress warning
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index f7f62ab..aec55d8 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -91,14 +91,14 @@
                               int left, int top, int width, int height,
                               GrPixelConfig, void* buffer);
 
-    virtual void onDrawIndexed(GrPrimitiveType type,
-                                   uint32_t startVertex,
-                                   uint32_t startIndex,
-                                   uint32_t vertexCount,
-                                   uint32_t indexCount);
-    virtual void onDrawNonIndexed(GrPrimitiveType type,
-                                      uint32_t vertexCount,
-                                      uint32_t numVertices);
+    virtual void onGpuDrawIndexed(GrPrimitiveType type,
+                                  uint32_t startVertex,
+                                  uint32_t startIndex,
+                                  uint32_t vertexCount,
+                                  uint32_t indexCount);
+    virtual void onGpuDrawNonIndexed(GrPrimitiveType type,
+                                     uint32_t vertexCount,
+                                     uint32_t numVertices);
     virtual void flushScissor(const GrIRect* rect);
     void clearStencil(uint32_t value, uint32_t mask);
     virtual void clearStencilClip(const GrIRect& rect);
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
index 65229dc..baa220b 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -166,7 +166,7 @@
         }
     }
 
-    uint32_t vertColor = (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit);
+    uint32_t vertColor = (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit);
     uint32_t prevVertColor = (fHWGeometryState.fVertexLayout &
                               kColor_VertexLayoutBit);
 
@@ -250,7 +250,7 @@
     int newColorOffset;
     int newTexCoordOffsets[kNumStages];
 
-    GrGLsizei newStride = VertexSizeAndOffsetsByStage(fGeometrySrc.fVertexLayout,
+    GrGLsizei newStride = VertexSizeAndOffsetsByStage(this->getGeomSrc().fVertexLayout,
                                                       newTexCoordOffsets,
                                                       &newColorOffset);
     int oldColorOffset;
@@ -266,7 +266,7 @@
     setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
 
     GrGLenum scalarType;
-    if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
+    if (this->getGeomSrc().fVertexLayout & kTextFormat_VertexLayoutBit) {
         scalarType = GrGLTextType;
     } else {
         scalarType = GrGLType;
@@ -289,7 +289,7 @@
                            ((GrGLTextType != GrGLType) &&
                                 (kTextFormat_VertexLayoutBit &
                                   (fHWGeometryState.fVertexLayout ^
-                                   fGeometrySrc.fVertexLayout)));
+                                   this->getGeomSrc().fVertexLayout)));
 
     if (posAndTexChange) {
         GR_GL(VertexPointer(2, scalarType, newStride, (GrGLvoid*)vertexOffset));
@@ -328,6 +328,6 @@
         GR_GL(DisableClientState(GR_GL_COLOR_ARRAY));
     }
 
-    fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
+    fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
     fHWGeometryState.fArrayPtrsDirty = false;
 }
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index 689c1fc..0b8aad7 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -501,7 +501,7 @@
 
 void GrGpuGLShaders::flushColor() {
     const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
-    if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
+    if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
         // color will be specified per-vertex as an attribute
         // invalidate the const vertex attrib color
         fHWDrawState.fColor = GrColor_ILLEGAL;
@@ -613,23 +613,25 @@
     int newColorOffset;
     int newTexCoordOffsets[kMaxTexCoords];
 
-    GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
-                                                  newTexCoordOffsets,
-                                                  &newColorOffset);
+    GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
+                                            this->getGeomSrc().fVertexLayout,
+                                            newTexCoordOffsets,
+                                            &newColorOffset);
     int oldColorOffset;
     int oldTexCoordOffsets[kMaxTexCoords];
-    GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
-                                                  oldTexCoordOffsets,
-                                                  &oldColorOffset);
+    GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
+                                            fHWGeometryState.fVertexLayout,
+                                            oldTexCoordOffsets,
+                                            &oldColorOffset);
     bool indexed = NULL != startIndex;
 
     int extraVertexOffset;
     int extraIndexOffset;
-    setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
+    this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
 
     GrGLenum scalarType;
     bool texCoordNorm;
-    if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
+    if (this->getGeomSrc().fVertexLayout & kTextFormat_VertexLayoutBit) {
         scalarType = GrGLTextType;
         texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
     } else {
@@ -654,7 +656,7 @@
                            (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
                                 (kTextFormat_VertexLayoutBit &
                                   (fHWGeometryState.fVertexLayout ^
-                                   fGeometrySrc.fVertexLayout)));
+                                   this->getGeomSrc().fVertexLayout)));
 
     if (posAndTexChange) {
         int idx = GrGLProgram::PositionAttributeIdx();
@@ -696,7 +698,7 @@
         GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
     }
 
-    fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
+    fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
     fHWGeometryState.fArrayPtrsDirty = false;
 }
 
@@ -704,7 +706,7 @@
     GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
 
     // Must initialize all fields or cache will have false negatives!
-    desc.fVertexLayout = fGeometrySrc.fVertexLayout;
+    desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
 
     desc.fEmitsPointSize = kPoints_PrimitiveType == type;
 
diff --git a/gpu/src/GrInOrderDrawBuffer.cpp b/gpu/src/GrInOrderDrawBuffer.cpp
index 7df1f23..a685620 100644
--- a/gpu/src/GrInOrderDrawBuffer.cpp
+++ b/gpu/src/GrInOrderDrawBuffer.cpp
@@ -23,30 +23,34 @@
 #include "GrGpu.h"
 
 GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrVertexBufferAllocPool* vertexPool,
-                                         GrIndexBufferAllocPool* indexPool) :
-        fDraws(&fDrawStorage),
-        fStates(&fStateStorage),
-        fClears(&fClearStorage),
-        fClips(&fClipStorage),
-        fClipSet(true),
+                                         GrIndexBufferAllocPool* indexPool)
+    : fDraws(&fDrawStorage)
+    , fStates(&fStateStorage)
+    , fClears(&fClearStorage)
+    , fClips(&fClipStorage)
+    , fClipSet(true)
 
-        fLastRectVertexLayout(0),
-        fQuadIndexBuffer(NULL),
-        fMaxQuads(0),
-        fCurrQuad(0),
+    , fLastRectVertexLayout(0)
+    , fQuadIndexBuffer(NULL)
+    , fMaxQuads(0)
+    , fCurrQuad(0)
 
-        fVertexPool(*vertexPool),
-        fCurrPoolVertexBuffer(NULL),
-        fCurrPoolStartVertex(0),
-        fIndexPool(*indexPool),
-        fCurrPoolIndexBuffer(NULL),
-        fCurrPoolStartIndex(0),
-        fReservedVertexBytes(0),
-        fReservedIndexBytes(0),
-        fUsedReservedVertexBytes(0),
-        fUsedReservedIndexBytes(0) {
+    , fVertexPool(*vertexPool)
+    , fIndexPool(*indexPool)
+    , fGeoPoolStateStack(&fGeoStackStorage) {
+    
     GrAssert(NULL != vertexPool);
     GrAssert(NULL != indexPool);
+
+    GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
+    poolState.fUsedPoolVertexBytes = 0;
+    poolState.fUsedPoolIndexBytes = 0;
+#if GR_DEBUG
+    poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
+    poolState.fPoolStartVertex = ~0;
+    poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
+    poolState.fPoolStartIndex = ~0;
+#endif
 }
 
 GrInOrderDrawBuffer::~GrInOrderDrawBuffer() {
@@ -150,19 +154,24 @@
             GrAssert(0 == lastDraw.fIndexCount % 6);
             GrAssert(0 == lastDraw.fStartIndex);
 
+            GeometryPoolState& poolState = fGeoPoolStateStack.back();
             bool clearSinceLastDraw =
                             fClears.count() && 
                             fClears.back().fBeforeDrawIdx == fDraws.count();
 
-            appendToPreviousDraw =  !clearSinceLastDraw &&
-                                    lastDraw.fVertexBuffer == fCurrPoolVertexBuffer &&
-                                   (fCurrQuad * 4 + lastDraw.fStartVertex) == fCurrPoolStartVertex;
+            appendToPreviousDraw =  
+                !clearSinceLastDraw &&
+                lastDraw.fVertexBuffer == poolState.fPoolVertexBuffer &&
+                (fCurrQuad * 4 + lastDraw.fStartVertex) == poolState.fPoolStartVertex;
+
             if (appendToPreviousDraw) {
                 lastDraw.fVertexCount += 4;
                 lastDraw.fIndexCount += 6;
                 fCurrQuad += 1;
-                GrAssert(0 == fUsedReservedVertexBytes);
-                fUsedReservedVertexBytes = 4 * vsize;
+                // we reserved above, so we should be the first
+                // use of this vertex reserveation.
+                GrAssert(0 == poolState.fUsedPoolVertexBytes);
+                poolState.fUsedPoolVertexBytes = 4 * vsize;
             }
         }
         if (!appendToPreviousDraw) {
@@ -179,11 +188,11 @@
     }
 }
 
-void GrInOrderDrawBuffer::drawIndexed(GrPrimitiveType primitiveType,
-                                      int startVertex,
-                                      int startIndex,
-                                      int vertexCount,
-                                      int indexCount) {
+void GrInOrderDrawBuffer::onDrawIndexed(GrPrimitiveType primitiveType,
+                                        int startVertex,
+                                        int startIndex,
+                                        int vertexCount,
+                                        int indexCount) {
 
     if (!vertexCount || !indexCount) {
         return;
@@ -191,6 +200,8 @@
 
     fCurrQuad = 0;
 
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+
     Draw& draw = fDraws.push_back();
     draw.fPrimitiveType = primitiveType;
     draw.fStartVertex   = startVertex;
@@ -208,52 +219,56 @@
         this->pushState();
     }
 
-    draw.fVertexLayout = fGeometrySrc.fVertexLayout;
-    switch (fGeometrySrc.fVertexSrc) {
+    draw.fVertexLayout = this->getGeomSrc().fVertexLayout;
+    switch (this->getGeomSrc().fVertexSrc) {
     case kBuffer_GeometrySrcType:
-        draw.fVertexBuffer = fGeometrySrc.fVertexBuffer;
+        draw.fVertexBuffer = this->getGeomSrc().fVertexBuffer;
         break;
-    case kReserved_GeometrySrcType: {
+    case kReserved_GeometrySrcType: // fallthrough
+    case kArray_GeometrySrcType: {
         size_t vertexBytes = (vertexCount + startVertex) *
-        VertexSize(fGeometrySrc.fVertexLayout);
-        fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes, vertexBytes);
-    } // fallthrough
-    case kArray_GeometrySrcType:
-        draw.fVertexBuffer = fCurrPoolVertexBuffer;
-        draw.fStartVertex += fCurrPoolStartVertex;
+                             VertexSize(this->getGeomSrc().fVertexLayout);
+        poolState.fUsedPoolVertexBytes = 
+                            GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
+        draw.fVertexBuffer = poolState.fPoolVertexBuffer;
+        draw.fStartVertex += poolState.fPoolStartVertex;
         break;
+    }
     default:
         GrCrash("unknown geom src type");
     }
     draw.fVertexBuffer->ref();
 
-    switch (fGeometrySrc.fIndexSrc) {
+    switch (this->getGeomSrc().fIndexSrc) {
     case kBuffer_GeometrySrcType:
-        draw.fIndexBuffer = fGeometrySrc.fIndexBuffer;
+        draw.fIndexBuffer = this->getGeomSrc().fIndexBuffer;
         break;
-    case kReserved_GeometrySrcType: {
+    case kReserved_GeometrySrcType: // fallthrough 
+    case kArray_GeometrySrcType: {
         size_t indexBytes = (indexCount + startIndex) * sizeof(uint16_t);
-        fUsedReservedIndexBytes = GrMax(fUsedReservedIndexBytes, indexBytes);
-    } // fallthrough
-    case kArray_GeometrySrcType:
-        draw.fIndexBuffer = fCurrPoolIndexBuffer;
-        draw.fStartIndex += fCurrPoolStartVertex;
+        poolState.fUsedPoolIndexBytes = 
+                            GrMax(poolState.fUsedPoolIndexBytes, indexBytes);
+        draw.fIndexBuffer = poolState.fPoolIndexBuffer;
+        draw.fStartIndex += poolState.fPoolStartVertex;
         break;
+    }
     default:
         GrCrash("unknown geom src type");
     }
     draw.fIndexBuffer->ref();
 }
 
-void GrInOrderDrawBuffer::drawNonIndexed(GrPrimitiveType primitiveType,
-                                         int startVertex,
-                                         int vertexCount) {
+void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType,
+                                           int startVertex,
+                                           int vertexCount) {
     if (!vertexCount) {
         return;
     }
 
     fCurrQuad = 0;
 
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+
     Draw& draw = fDraws.push_back();
     draw.fPrimitiveType = primitiveType;
     draw.fStartVertex   = startVertex;
@@ -271,21 +286,21 @@
         this->pushState();
     }
 
-    draw.fVertexLayout = fGeometrySrc.fVertexLayout;
-    switch (fGeometrySrc.fVertexSrc) {
+    draw.fVertexLayout = this->getGeomSrc().fVertexLayout;
+    switch (this->getGeomSrc().fVertexSrc) {
     case kBuffer_GeometrySrcType:
-        draw.fVertexBuffer = fGeometrySrc.fVertexBuffer;
+        draw.fVertexBuffer = this->getGeomSrc().fVertexBuffer;
         break;
-    case kReserved_GeometrySrcType: {
+    case kReserved_GeometrySrcType: // fallthrough
+    case kArray_GeometrySrcType: {
         size_t vertexBytes = (vertexCount + startVertex) *
-        VertexSize(fGeometrySrc.fVertexLayout);
-        fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes,
-                                         vertexBytes);
-    } // fallthrough
-    case kArray_GeometrySrcType:
-        draw.fVertexBuffer = fCurrPoolVertexBuffer;
-        draw.fStartVertex += fCurrPoolStartVertex;
+                             VertexSize(this->getGeomSrc().fVertexLayout);
+        poolState.fUsedPoolVertexBytes = 
+                            GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
+        draw.fVertexBuffer = poolState.fPoolVertexBuffer;
+        draw.fStartVertex += poolState.fPoolStartVertex;
         break;
+    }
     default:
         GrCrash("unknown geom src type");
     }
@@ -311,7 +326,9 @@
 }
 
 void GrInOrderDrawBuffer::reset() {
-    GrAssert(!fReservedGeometry.fLocked);
+    GrAssert(1 == fGeoPoolStateStack.count());
+    this->resetVertexSource();
+    this->resetIndexSource();
     uint32_t numStates = fStates.count();
     for (uint32_t i = 0; i < numStates; ++i) {
         const DrState& dstate = this->accessSavedDrawState(fStates[i]);
@@ -341,7 +358,8 @@
 }
 
 void GrInOrderDrawBuffer::playback(GrDrawTarget* target) {
-    GrAssert(!fReservedGeometry.fLocked);
+    GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc);
+    GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc);
     GrAssert(NULL != target);
     GrAssert(target != this); // not considered and why?
 
@@ -355,9 +373,7 @@
 
     GrDrawTarget::AutoStateRestore asr(target);
     GrDrawTarget::AutoClipRestore acr(target);
-    // important to not mess with reserve/lock geometry in the target with this
-    // on the stack.
-    GrDrawTarget::AutoGeometrySrcRestore agsr(target);
+    AutoGeometryPush agp(target);
 
     int currState = ~0;
     int currClip  = ~0;
@@ -435,89 +451,143 @@
     return flush;
 }
 
-bool GrInOrderDrawBuffer::onAcquireGeometry(GrVertexLayout vertexLayout,
-                                            void**         vertices,
-                                            void**         indices) {
-    GrAssert(!fReservedGeometry.fLocked);
-    if (fReservedGeometry.fVertexCount) {
-        GrAssert(NULL != vertices);
-        GrAssert(0 == fReservedVertexBytes);
-        GrAssert(0 == fUsedReservedVertexBytes);
+bool GrInOrderDrawBuffer::onReserveVertexSpace(GrVertexLayout vertexLayout,
+                                               int vertexCount,
+                                               void** vertices) {
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+    GrAssert(vertexCount > 0);
+    GrAssert(NULL != vertices);
+    GrAssert(0 == poolState.fUsedPoolVertexBytes);
+    
+    *vertices = fVertexPool.makeSpace(vertexLayout,
+                                      vertexCount,
+                                      &poolState.fPoolVertexBuffer,
+                                      &poolState.fPoolStartVertex);
+    return NULL != *vertices;
+}
+    
+bool GrInOrderDrawBuffer::onReserveIndexSpace(int indexCount, void** indices) {
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+    GrAssert(indexCount > 0);
+    GrAssert(NULL != indices);
+    GrAssert(0 == poolState.fUsedPoolIndexBytes);
 
-        fReservedVertexBytes = VertexSize(vertexLayout) *
-                               fReservedGeometry.fVertexCount;
-        *vertices = fVertexPool.makeSpace(vertexLayout,
-                                          fReservedGeometry.fVertexCount,
-                                          &fCurrPoolVertexBuffer,
-                                          &fCurrPoolStartVertex);
-        if (NULL == *vertices) {
-            return false;
-        }
-    }
-    if (fReservedGeometry.fIndexCount) {
-        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;
-        }
-    }
-    return true;
+    *indices = fIndexPool.makeSpace(indexCount,
+                                    &poolState.fPoolIndexBuffer,
+                                    &poolState.fPoolStartIndex);
+    return NULL != *indices;
 }
 
-void GrInOrderDrawBuffer::onReleaseGeometry() {
-    GrAssert(fUsedReservedVertexBytes <= fReservedVertexBytes);
-    GrAssert(fUsedReservedIndexBytes <= fReservedIndexBytes);
-
-    size_t vertexSlack = fReservedVertexBytes - fUsedReservedVertexBytes;
-    fVertexPool.putBack(vertexSlack);
-
-    size_t indexSlack = fReservedIndexBytes - fUsedReservedIndexBytes;
-    fIndexPool.putBack(indexSlack);
-
-    fReservedVertexBytes = 0;
-    fReservedIndexBytes  = 0;
-    fUsedReservedVertexBytes = 0;
-    fUsedReservedIndexBytes  = 0;
-    fCurrPoolVertexBuffer = 0;
-    fCurrPoolStartVertex = 0;
-
+void GrInOrderDrawBuffer::releaseReservedVertexSpace() {
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+    const GeometrySrcState& geoSrc = this->getGeomSrc(); 
+    
+    GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
+    
+    size_t reservedVertexBytes = VertexSize(geoSrc.fVertexLayout) * 
+                                 geoSrc.fVertexCount;
+    fVertexPool.putBack(reservedVertexBytes - 
+                        poolState.fUsedPoolVertexBytes);
+    poolState.fUsedPoolVertexBytes = 0;
+    poolState.fPoolVertexBuffer = 0;
 }
 
+void GrInOrderDrawBuffer::releaseReservedIndexSpace() {
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+    const GeometrySrcState& geoSrc = this->getGeomSrc(); 
+
+    GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
+    
+    size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount;
+    fIndexPool.putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes);
+    poolState.fUsedPoolIndexBytes = 0;
+    poolState.fPoolStartVertex = 0;
+}
+    
 void GrInOrderDrawBuffer::onSetVertexSourceToArray(const void* vertexArray,
                                                    int vertexCount) {
-    GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
+
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+    GrAssert(0 == poolState.fUsedPoolVertexBytes);
 #if GR_DEBUG
     bool success =
 #endif
-    fVertexPool.appendVertices(fGeometrySrc.fVertexLayout,
+    fVertexPool.appendVertices(this->getGeomSrc().fVertexLayout,
                                vertexCount,
                                vertexArray,
-                               &fCurrPoolVertexBuffer,
-                               &fCurrPoolStartVertex);
+                               &poolState.fPoolVertexBuffer,
+                               &poolState.fPoolStartVertex);
     GR_DEBUGASSERT(success);
 }
 
 void GrInOrderDrawBuffer::onSetIndexSourceToArray(const void* indexArray,
                                                   int indexCount) {
-    GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+    GrAssert(0 == poolState.fUsedPoolIndexBytes);
 #if GR_DEBUG
     bool success =
 #endif
     fIndexPool.appendIndices(indexCount,
                              indexArray,
-                             &fCurrPoolIndexBuffer,
-                             &fCurrPoolStartIndex);
+                             &poolState.fPoolIndexBuffer,
+                             &poolState.fPoolStartIndex);
     GR_DEBUGASSERT(success);
 }
 
+void GrInOrderDrawBuffer::geometrySourceWillPush() {
+    GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
+    poolState.fUsedPoolVertexBytes = 0;
+    poolState.fUsedPoolIndexBytes = 0;
+#if GR_DEBUG
+    poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
+    poolState.fPoolStartVertex = ~0;
+    poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
+    poolState.fPoolStartIndex = ~0;
+#endif
+}
+
+void GrInOrderDrawBuffer::releaseVertexArray() {
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+    const GeometrySrcState& geoSrc = this->getGeomSrc(); 
+    
+    size_t reservedVertexBytes = VertexSize(geoSrc.fVertexLayout) * 
+    geoSrc.fVertexCount;
+    fVertexPool.putBack(reservedVertexBytes - poolState.fUsedPoolVertexBytes);
+    
+    poolState.fUsedPoolVertexBytes = 0;
+}
+
+void GrInOrderDrawBuffer::releaseIndexArray() {
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+    const GeometrySrcState& geoSrc = this->getGeomSrc(); 
+    
+    size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount;
+    fIndexPool.putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes);
+    
+    poolState.fUsedPoolIndexBytes = 0;
+}
+
+void GrInOrderDrawBuffer::geometrySourceWillPop(
+                                        const GeometrySrcState& restoredState) {
+    GrAssert(fGeoPoolStateStack.count() > 1);
+    fGeoPoolStateStack.pop_back();
+    GeometryPoolState& poolState = fGeoPoolStateStack.back();
+    // we have to assume that any slack we had in our vertex/index data
+    // is now unreleasable because data may have been appended later in the
+    // pool.
+    if (kReserved_GeometrySrcType == restoredState.fVertexSrc ||
+        kArray_GeometrySrcType == restoredState.fVertexSrc) {
+        poolState.fUsedPoolVertexBytes = 
+            VertexSize(restoredState.fVertexLayout) * 
+            restoredState.fVertexCount;
+    }
+    if (kReserved_GeometrySrcType == restoredState.fIndexSrc ||
+        kArray_GeometrySrcType == restoredState.fIndexSrc) {
+        poolState.fUsedPoolVertexBytes = sizeof(uint16_t) * 
+                                         restoredState.fIndexCount;
+    }
+}
+
 bool GrInOrderDrawBuffer::needsNewState() const {
      if (fStates.empty()) {
         return true;
diff --git a/gpu/src/GrTextContext.cpp b/gpu/src/GrTextContext.cpp
index 41e4a85..5d0f9f7 100644
--- a/gpu/src/GrTextContext.cpp
+++ b/gpu/src/GrTextContext.cpp
@@ -72,7 +72,7 @@
 
         fDrawTarget->drawIndexed(kTriangles_PrimitiveType,
                                  0, 0, fCurrVertex, nIndices);
-        fDrawTarget->releaseReservedGeometry();
+        fDrawTarget->resetVertexSource();
         fVertices = NULL;
         fMaxVertices = 0;
         fCurrVertex = 0;
@@ -284,10 +284,9 @@
             // don't exceed the limit of the index buffer
             fMaxVertices = maxQuadVertices;
         }
-        bool success = fDrawTarget->reserveAndLockGeometry(fVertexLayout,
-                                                           fMaxVertices, 0,
-                                                   GrTCast<void**>(&fVertices),
-                                                           NULL);
+        bool success = fDrawTarget->reserveVertexSpace(fVertexLayout, 
+                                                   fMaxVertices,
+                                                   GrTCast<void**>(&fVertices));
         GrAlwaysAssert(success);
     }