Refactor tracking of bound vbufs and ibufs and vertex attrib arrays.
Review URL: https://codereview.appspot.com/7359045

git-svn-id: http://skia.googlecode.com/svn/trunk@7779 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index f14238c..baa6e44 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -178,6 +178,8 @@
 
     fProgramCache = SkNEW_ARGS(ProgramCache, (this->glContextInfo()));
 
+    fHWGeometryState.setMaxAttribArrays(this->glCaps().maxVertexAttributes());
+
     fLastSuccessfulStencilFmtIdx = 0;
     if (false) { // avoid bit rot, suppress warning
         fbo_test(this->glInterface(), 0, 0);
@@ -446,10 +448,7 @@
     fHWStencilSettings.invalidate();
     fHWStencilTestEnabled = kUnknown_TriState;
 
-    fHWGeometryState.fIndexBuffer = NULL;
-    fHWGeometryState.fVertexBuffer = NULL;
-
-    fHWGeometryState.fArrayPtrsDirty = true;
+    fHWGeometryState.invalidate();
 
     fHWBoundRenderTarget = NULL;
 
@@ -474,28 +473,6 @@
         GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, GR_GL_FALSE));
     }
 
-    fHWGeometryState.fVertexOffset = ~0U;
-
-    // Third party GL code may have left vertex attributes enabled. Some GL
-    // implementations (osmesa) may read vetex attributes that are not required
-    // by the current shader. Therefore, we have to ensure that only the
-    // attributes we require for the current draw are enabled or we may cause an
-    // invalid read.
-
-    // Disable all vertex layout bits so that next flush will assume all
-    // optional vertex attributes are disabled.
-    fHWGeometryState.fVertexLayout = 0;
-
-    // We always use the this attribute and assume it is always enabled.
-    int posAttrIdx = GrGLProgram::PositionAttributeIdx();
-    GL_CALL(EnableVertexAttribArray(posAttrIdx));
-    // Disable all other vertex attributes.
-    for  (int va = 0; va < this->glCaps().maxVertexAttributes(); ++va) {
-        if (va != posAttrIdx) {
-            GL_CALL(DisableVertexAttribArray(va));
-        }
-    }
-
     fHWProgramID = 0;
     fSharedGLProgramState.invalidate();
 }
@@ -1253,26 +1230,26 @@
     GL_CALL(GenBuffers(1, &id));
     if (id) {
         GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, id));
-        fHWGeometryState.fArrayPtrsDirty = true;
         CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
         // make sure driver can allocate memory for this buffer
         GL_ALLOC_CALL(this->glInterface(),
                       BufferData(GR_GL_ARRAY_BUFFER,
                                  size,
                                  NULL,   // data ptr
-                                 dynamic ? GR_GL_DYNAMIC_DRAW :
-                                           GR_GL_STATIC_DRAW));
+                                 dynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
         if (CHECK_ALLOC_ERROR(this->glInterface()) != GR_GL_NO_ERROR) {
             GL_CALL(DeleteBuffers(1, &id));
             // deleting bound buffer does implicit bind to 0
-            fHWGeometryState.fVertexBuffer = NULL;
+            fHWGeometryState.setVertexBufferID(0);
             return NULL;
         }
         static const bool kIsWrapped = false;
-        GrGLVertexBuffer* vertexBuffer = SkNEW_ARGS(GrGLVertexBuffer,
-                                                    (this, kIsWrapped, id,
-                                                     size, dynamic));
-        fHWGeometryState.fVertexBuffer = vertexBuffer;
+        GrGLVertexBuffer* vertexBuffer = SkNEW_ARGS(GrGLVertexBuffer, (this,
+                                                                       false,
+                                                                       id,
+                                                                       size,
+                                                                       dynamic));
+        fHWGeometryState.setVertexBufferID(id);
         return vertexBuffer;
     }
     return NULL;
@@ -1294,13 +1271,13 @@
         if (CHECK_ALLOC_ERROR(this->glInterface()) != GR_GL_NO_ERROR) {
             GL_CALL(DeleteBuffers(1, &id));
             // deleting bound buffer does implicit bind to 0
-            fHWGeometryState.fIndexBuffer = NULL;
+            fHWGeometryState.setIndexBufferID(0);
             return NULL;
         }
         static const bool kIsWrapped = false;
         GrIndexBuffer* indexBuffer = SkNEW_ARGS(GrGLIndexBuffer,
                                                 (this, kIsWrapped, id, size, dynamic));
-        fHWGeometryState.fIndexBuffer = indexBuffer;
+        fHWGeometryState.setIndexBufferID(id);
         return indexBuffer;
     }
     return NULL;
@@ -1660,16 +1637,14 @@
 #endif
 
 void GrGpuGL::onGpuDraw(const DrawInfo& info) {
-    int extraStartIndexOffset;
-    this->setupGeometry(info, &extraStartIndexOffset);
+    size_t indexOffsetInBytes;
+    this->setupGeometry(info, &indexOffsetInBytes);
 
     GrAssert((size_t)info.primitiveType() < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
-    GrAssert(NULL != fHWGeometryState.fVertexBuffer);
 
     if (info.isIndexed()) {
-        GrAssert(NULL != fHWGeometryState.fIndexBuffer);
-        GrGLvoid* indices = (GrGLvoid*)(sizeof(uint16_t) * (info.startIndex() +
-                                                            extraStartIndexOffset));
+        GrGLvoid* indices =
+            reinterpret_cast<GrGLvoid*>(indexOffsetInBytes + sizeof(uint16_t) * info.startIndex());
         // info.startVertex() was accounted for by setupGeometry.
         GL_CALL(DrawElements(gPrimitiveType2GLMode[info.primitiveType()],
                              info.indexCount(),
@@ -2171,29 +2146,19 @@
 }
 
 void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
-    if (fHWGeometryState.fVertexBuffer != buffer) {
-        fHWGeometryState.fArrayPtrsDirty = true;
-        fHWGeometryState.fVertexBuffer = buffer;
-    }
+    fHWGeometryState.setVertexBufferID(buffer->bufferID());
 }
 
 void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
-    if (fHWGeometryState.fVertexBuffer == buffer) {
-        // deleting bound buffer does implied bind to 0
-        fHWGeometryState.fVertexBuffer = NULL;
-        fHWGeometryState.fArrayPtrsDirty = true;
-    }
+    fHWGeometryState.notifyVertexBufferDelete(buffer);
 }
 
 void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
-    fHWGeometryState.fIndexBuffer = buffer;
+    fHWGeometryState.setIndexBufferID(buffer->bufferID());
 }
 
 void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
-    if (fHWGeometryState.fIndexBuffer == buffer) {
-        // deleting bound buffer does implied bind to 0
-        fHWGeometryState.fIndexBuffer = NULL;
-    }
+    fHWGeometryState.notifyIndexBufferDelete(buffer);
 }
 
 void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
@@ -2338,52 +2303,48 @@
     }
 }
 
-void GrGpuGL::setBuffers(bool indexed,
-                         int* extraVertexOffset,
-                         int* extraIndexOffset) {
+GrGLVertexBuffer* GrGpuGL::setBuffers(bool indexed,
+                                      size_t* vertexOffsetInBytes,
+                                      size_t* indexOffsetInBytes) {
 
-    GrAssert(NULL != extraVertexOffset);
+    GrAssert(NULL != vertexOffsetInBytes);
 
     const GeometryPoolState& geoPoolState = this->getGeomPoolState();
 
     GrGLVertexBuffer* vbuf;
     switch (this->getGeomSrc().fVertexSrc) {
-    case kBuffer_GeometrySrcType:
-        *extraVertexOffset = 0;
-        vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer;
-        break;
-    case kArray_GeometrySrcType:
-    case kReserved_GeometrySrcType:
-        this->finalizeReservedVertices();
-        *extraVertexOffset = geoPoolState.fPoolStartVertex;
-        vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer;
-        break;
-    default:
-        vbuf = NULL; // suppress warning
-        GrCrash("Unknown geometry src type!");
+        case kBuffer_GeometrySrcType:
+            *vertexOffsetInBytes = 0;
+            vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer;
+            break;
+        case kArray_GeometrySrcType:
+        case kReserved_GeometrySrcType:
+            this->finalizeReservedVertices();
+            *vertexOffsetInBytes = geoPoolState.fPoolStartVertex * this->getGeomSrc().fVertexSize;
+            vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer;
+            break;
+        default:
+            vbuf = NULL; // suppress warning
+            GrCrash("Unknown geometry src type!");
     }
 
     GrAssert(NULL != vbuf);
     GrAssert(!vbuf->isLocked());
-    if (fHWGeometryState.fVertexBuffer != vbuf) {
-        GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, vbuf->bufferID()));
-        fHWGeometryState.fArrayPtrsDirty = true;
-        fHWGeometryState.fVertexBuffer = vbuf;
-    }
+    *vertexOffsetInBytes += vbuf->baseOffset();
 
     if (indexed) {
-        GrAssert(NULL != extraIndexOffset);
+        GrAssert(NULL != indexOffsetInBytes);
 
         GrGLIndexBuffer* ibuf;
         switch (this->getGeomSrc().fIndexSrc) {
         case kBuffer_GeometrySrcType:
-            *extraIndexOffset = 0;
+            *indexOffsetInBytes = 0;
             ibuf = (GrGLIndexBuffer*)this->getGeomSrc().fIndexBuffer;
             break;
         case kArray_GeometrySrcType:
         case kReserved_GeometrySrcType:
             this->finalizeReservedIndices();
-            *extraIndexOffset = geoPoolState.fPoolStartIndex;
+            *indexOffsetInBytes = geoPoolState.fPoolStartIndex * sizeof(GrGLushort);
             ibuf = (GrGLIndexBuffer*) geoPoolState.fPoolIndexBuffer;
             break;
         default:
@@ -2393,9 +2354,53 @@
 
         GrAssert(NULL != ibuf);
         GrAssert(!ibuf->isLocked());
-        if (fHWGeometryState.fIndexBuffer != ibuf) {
-            GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, ibuf->bufferID()));
-            fHWGeometryState.fIndexBuffer = ibuf;
+        if (!fHWGeometryState.isIndexBufferIDBound(ibuf->bufferID())) {
+            ibuf->bind();
+            fHWGeometryState.setIndexBufferID(ibuf->bufferID());
         }
     }
+    return vbuf;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrGpuGL::HWGeometryState::AttribArray::set(const GrGpuGL* gpu,
+                                                HWGeometryState* geoState,
+                                                int index,
+                                                GrGLVertexBuffer* buffer,
+                                                GrGLint size,
+                                                GrGLenum type,
+                                                GrGLboolean normalized,
+                                                GrGLsizei stride,
+                                                GrGLvoid* offset) {
+    if (!fEnableIsValid || !fEnabled) {
+        GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(index));
+        fEnableIsValid = true;
+        fEnabled = true;
+    }
+    if (!fAttribPointerIsValid ||
+        fVertexBufferID != buffer->bufferID() ||
+        fSize != size ||
+        fNormalized != normalized ||
+        fStride != stride ||
+        offset != fOffset) {
+
+        GrGLuint bufferID = buffer->bufferID();
+        if (!geoState->isVertexBufferIDBound(bufferID)) {
+            buffer->bind();
+            geoState->setVertexBufferID(bufferID);
+        }
+        GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index,
+                                                           size,
+                                                           type,
+                                                           normalized,
+                                                           stride,
+                                                           offset));
+        fAttribPointerIsValid = true;
+        fVertexBufferID = bufferID;
+        fSize = size;
+        fNormalized = normalized;
+        fStride = stride;
+        fOffset = offset;
+    }
 }