git-svn-id: http://skia.googlecode.com/svn/trunk@783 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index d366953..7a83ac8 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -47,8 +47,6 @@
     GL_ONE_MINUS_DST_ALPHA,
 };
 
-
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static bool gPrintStartupSpew;
@@ -88,6 +86,14 @@
 }
 
 GrGpuGL::GrGpuGL() {
+
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+    fClientArrayVB = NULL;
+    fClientArrayIB = NULL;
+    fOversizeVBDrawCnt = 0;
+    fOversizeIBDrawCnt = 0;
+#endif
+
     if (gPrintStartupSpew) {
         GrPrintf("------------------------- create GrGpuGL %p --------------\n",
                  this);
@@ -366,6 +372,10 @@
 }
 
 GrGpuGL::~GrGpuGL() {
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+    GrSafeUnref(fClientArrayVB);
+    GrSafeUnref(fClientArrayIB);
+#endif
 }
 
 void GrGpuGL::resetContextHelper() {
@@ -425,6 +435,7 @@
     fHWGeometryState.fVertexBuffer = NULL;
     GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
     GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+    fHWGeometryState.fArrayPtrsDirty = true;
 
     fHWDrawState.fRenderTarget = NULL;
 }
@@ -434,6 +445,64 @@
     resetContextHelper();
 }
 
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+void GrGpuGL::putClientVertexDataInBuffer(const void* vertexData, size_t vertexDataSize) {
+    static const size_t MIN_VB_SIZE = 1 << 11;
+    static const int MAX_OVERSIZE_VB_DRAWS = 100;
+
+    if (NULL != vertexData) {
+        size_t currMinVBSize = GrMax(MIN_VB_SIZE, vertexDataSize);
+        // if we don't have a VB, its too small, or too big, create a new one
+        if (NULL == fClientArrayVB ||
+            fClientArrayVB->size() < currMinVBSize  ||
+            (fOversizeVBDrawCnt >= MAX_OVERSIZE_VB_DRAWS &&
+             currMinVBSize == MIN_VB_SIZE &&
+             fClientArrayVB->size() > MIN_VB_SIZE)) {
+
+            if (fHWGeometryState.fVertexBuffer == fClientArrayVB) {
+                fHWGeometryState.fVertexBuffer = NULL;
+                fHWGeometryState.fArrayPtrsDirty = true;
+            }
+            GrSafeUnref(fClientArrayVB);
+            fClientArrayVB = (GrGLVertexBuffer*)createVertexBuffer(currMinVBSize, true);
+            fOversizeVBDrawCnt = 0;
+                GrPrintf("Realloc VB 0%08x\n", currMinVBSize);
+        }
+        fClientArrayVB->updateData(vertexData, vertexDataSize);
+        if (currMinVBSize == MIN_VB_SIZE && fClientArrayVB->size() > MIN_VB_SIZE) {
+            ++fOversizeVBDrawCnt;
+        }
+    }
+}
+
+void GrGpuGL::putClientIndexDataInBuffer(const void* indexData, size_t indexDataSize) {
+    static const size_t MIN_IB_SIZE = 1 << 8;
+    static const int MAX_OVERSIZE_IB_DRAWS = 100;
+
+    if (NULL != indexData) {
+        size_t currMinIBSize = GrMax(MIN_IB_SIZE, indexDataSize);
+        // if we don't have a IB, its too small, or too big, create a new one
+        if (NULL == fClientArrayIB ||
+            fClientArrayIB->size() < currMinIBSize  ||
+            (fOversizeIBDrawCnt >= MAX_OVERSIZE_IB_DRAWS &&
+             currMinIBSize == MIN_IB_SIZE &&
+             fClientArrayIB->size() > MIN_IB_SIZE)) {
+
+            if (fHWGeometryState.fIndexBuffer == fClientArrayIB) {
+                fHWGeometryState.fIndexBuffer = NULL;
+            }
+            GrSafeUnref(fClientArrayIB);
+            fClientArrayIB = (GrGLIndexBuffer*)createIndexBuffer(currMinIBSize, true);
+            fOversizeIBDrawCnt = 0;
+        }
+        fClientArrayIB->updateData(indexData, indexDataSize);
+        if (currMinIBSize == MIN_IB_SIZE && fClientArrayIB->size() > MIN_IB_SIZE) {
+            ++fOversizeIBDrawCnt;
+        }
+    }
+}
+#endif
+
 GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
                                                 intptr_t platformRenderTarget,
                                                 int width, int height) {
@@ -921,6 +990,7 @@
     GR_GL(GenBuffers(1, &id));
     if (id) {
         GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
+        fHWGeometryState.fArrayPtrsDirty = true;
         GrGLClearErr();
         // make sure driver can allocate memory for this buffer
         GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
@@ -1132,12 +1202,20 @@
     GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
 
     GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
+
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+    if (kBuffer_GeometrySrcType != fGeometrySrc.fIndexSrc) {
+        // we accounted for the startIndex when shoving data into a vb
+        indices = NULL;
+    }
+#else
     if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
         indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
     } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
         indices = (GLvoid*)((intptr_t)indices +
                             (intptr_t)fGeometrySrc.fIndexArray);
     }
+#endif
 
     GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
                        GL_UNSIGNED_SHORT, indices));
@@ -1537,7 +1615,10 @@
 }
 
 void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
-    fHWGeometryState.fVertexBuffer = buffer;
+    if (fHWGeometryState.fVertexBuffer != buffer) {
+        fHWGeometryState.fArrayPtrsDirty = true;
+        fHWGeometryState.fVertexBuffer = buffer;
+    }
 }
 
 void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
@@ -1547,6 +1628,7 @@
     if (fHWGeometryState.fVertexBuffer == buffer) {
         // deleting bound buffer does implied bind to 0
         fHWGeometryState.fVertexBuffer = NULL;
+        fHWGeometryState.fArrayPtrsDirty = true;
     }
 }
 
@@ -1692,3 +1774,85 @@
             return false;
     }
 }
+
+
+const GLvoid* GrGpuGL::setBuffersAndGetVertexStart(int vertexStride, int startVertex,
+                                                   int startIndex, int vertexCount,
+                                                   int indexCount) {
+    const GLvoid* posPtr = (GLvoid*)(vertexStride * startVertex);
+
+    if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
+        GrAssert(NULL != fGeometrySrc.fVertexBuffer);
+        GrAssert(!fGeometrySrc.fVertexBuffer->isLocked());
+        if (fHWGeometryState.fVertexBuffer != fGeometrySrc.fVertexBuffer) {
+            GrGLVertexBuffer* buf =
+                            (GrGLVertexBuffer*)fGeometrySrc.fVertexBuffer;
+            GR_GL(BindBuffer(GL_ARRAY_BUFFER, buf->bufferID()));
+            fHWGeometryState.fArrayPtrsDirty = true;
+            fHWGeometryState.fVertexBuffer = fGeometrySrc.fVertexBuffer;
+        }
+    } else {
+        if (kArray_GeometrySrcType == fGeometrySrc.fVertexSrc) {
+            posPtr = (void*)((intptr_t)fGeometrySrc.fVertexArray +
+                             (intptr_t)posPtr);
+        } else {
+            GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fVertexSrc);
+            posPtr = (void*)((intptr_t)fVertices.get() + (intptr_t)posPtr);
+        }
+    #if GR_GL_NO_CLIENT_SIDE_ARRAYS
+        putClientVertexDataInBuffer(posPtr, vertexCount * vertexStride);
+        posPtr = NULL;
+        if (fHWGeometryState.fVertexBuffer != fClientArrayVB) {
+            GR_GL(BindBuffer(GL_ARRAY_BUFFER, fClientArrayVB->bufferID()));
+            fHWGeometryState.fArrayPtrsDirty = true;
+            fHWGeometryState.fVertexBuffer = fClientArrayVB;
+        }
+    #else
+        if (NULL != fHWGeometryState.fVertexBuffer) {
+            GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
+            fHWGeometryState.fArrayPtrsDirty = true;
+            fHWGeometryState.fVertexBuffer = NULL;
+        }
+    #endif
+    }
+
+    if (0 != indexCount) {
+
+        if (kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc) {
+            GrAssert(NULL != fGeometrySrc.fIndexBuffer);
+            GrAssert(!fGeometrySrc.fIndexBuffer->isLocked());
+            if (fHWGeometryState.fIndexBuffer != fGeometrySrc.fIndexBuffer) {
+                GrGLIndexBuffer* buf =
+                (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
+                GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->bufferID()));
+                fHWGeometryState.fIndexBuffer = fGeometrySrc.fIndexBuffer;
+            }
+        }
+        #if GR_GL_NO_CLIENT_SIDE_ARRAYS
+        else {
+            const uint16_t* indices;
+            if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
+                indices = reinterpret_cast<const uint16_t*>(fGeometrySrc.fIndexArray);
+            } else {
+                GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc);
+                indices = reinterpret_cast<const uint16_t*>(fIndices.get());
+            }
+            // we shove just the referenced part of the index data into the begining
+            // of the buffer and drawIndexedHelper ignores startIndex.
+            putClientIndexDataInBuffer(indices + startIndex, indexCount  * sizeof(uint16_t));
+            if (fHWGeometryState.fIndexBuffer != fClientArrayIB) {
+                GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, fClientArrayIB->bufferID()));
+                fHWGeometryState.fIndexBuffer = fClientArrayIB;
+            }
+        }
+        #else
+        else if (NULL != fHWGeometryState.fIndexBuffer) {
+            // we rely on drawIndexedHelper to pass to client side
+            // ptr to DrawElements
+            GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+            fHWGeometryState.fIndexBuffer = NULL;
+        }
+        #endif
+    }
+    return posPtr;
+}