Refactor tracking of bound vbufs and ibufs and vertex attrib arrays.
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 19 Feb 2013 20:17:28 +0000 (20:17 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 19 Feb 2013 20:17:28 +0000 (20:17 +0000)
Review URL: https://codereview.appspot.com/7359045

git-svn-id: http://skia.googlecode.com/svn/trunk@7779 2bbb7eff-a529-9590-31e7-b0007b416f81

src/gpu/gl/GrGLIndexBuffer.cpp
src/gpu/gl/GrGLIndexBuffer.h
src/gpu/gl/GrGLProgram.cpp
src/gpu/gl/GrGLProgram.h
src/gpu/gl/GrGLVertexBuffer.cpp
src/gpu/gl/GrGLVertexBuffer.h
src/gpu/gl/GrGpuGL.cpp
src/gpu/gl/GrGpuGL.h
src/gpu/gl/GrGpuGL_program.cpp

index 561133add857a6105162c756e39975024005dcb4..035bfaccce49497a144d367cf949507eaf6ca204 100644 (file)
@@ -48,10 +48,6 @@ void GrGLIndexBuffer::bind() const {
     GPUGL->notifyIndexBufferBind(this);
 }
 
-GrGLuint GrGLIndexBuffer::bufferID() const {
-    return fBufferID;
-}
-
 void* GrGLIndexBuffer::lock() {
     GrAssert(fBufferID);
     GrAssert(!isLocked());
index 936e650e5612b0451cfb5f36c77f6f00e6de9f59..5182573abfe419d7cefc00bbbdbc8d8933a28d59 100644 (file)
@@ -19,9 +19,18 @@ class GrGLIndexBuffer : public GrIndexBuffer {
 
 public:
 
+    GrGLIndexBuffer(GrGpuGL* gpu,
+                    bool isWrapped,
+                    GrGLuint id,
+                    size_t sizeInBytes,
+                    bool dynamic);
+
     virtual ~GrGLIndexBuffer() { this->release(); }
 
-    GrGLuint bufferID() const;
+    GrGLuint bufferID() const { return fBufferID; }
+    size_t baseOffset() const { return 0; }
+
+    void bind() const;
 
     // overrides of GrIndexBuffer
     virtual void* lock();
@@ -31,24 +40,16 @@ public:
     virtual bool updateData(const void* src, size_t srcSizeInBytes);
 
 protected:
-    GrGLIndexBuffer(GrGpuGL* gpu,
-                    bool isWrapped,
-                    GrGLuint id,
-                    size_t sizeInBytes,
-                    bool dynamic);
 
     // overrides of GrResource
     virtual void onAbandon() SK_OVERRIDE;
     virtual void onRelease() SK_OVERRIDE;
 
 private:
-    void bind() const;
 
     GrGLuint     fBufferID;
     void*        fLockPtr;
 
-    friend class GrGpuGL;
-
     typedef GrIndexBuffer INHERITED;
 };
 
index 8620c5cb4a325a3666db9a8633224851ba7ad7b3..ccea34eae59316c5653d489056e6f8bb098c7d60 100644 (file)
@@ -966,12 +966,12 @@ bool GrGLProgram::bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& buil
 
     // Bind the attrib locations to same values for all shaders
     GL_CALL(BindAttribLocation(fProgramID,
-                               PositionAttributeIdx(),
+                               kPositionAttributeIndex,
                                builder.positionAttribute().c_str()));
-    GL_CALL(BindAttribLocation(fProgramID, TexCoordAttributeIdx(), TEX_ATTR_NAME));
-    GL_CALL(BindAttribLocation(fProgramID, ColorAttributeIdx(), COL_ATTR_NAME));
-    GL_CALL(BindAttribLocation(fProgramID, CoverageAttributeIdx(), COV_ATTR_NAME));
-    GL_CALL(BindAttribLocation(fProgramID, EdgeAttributeIdx(), EDGE_ATTR_NAME));
+    GL_CALL(BindAttribLocation(fProgramID, kTexCoordAttributeIndex, TEX_ATTR_NAME));
+    GL_CALL(BindAttribLocation(fProgramID, kColorAttributeIndex, COL_ATTR_NAME));
+    GL_CALL(BindAttribLocation(fProgramID, kCoverageAttributeIndex, COV_ATTR_NAME));
+    GL_CALL(BindAttribLocation(fProgramID, kEdgeAttributeIndex, EDGE_ATTR_NAME));
 
     GL_CALL(LinkProgram(fProgramID));
 
@@ -1067,7 +1067,7 @@ void GrGLProgram::setColor(const GrDrawState& drawState,
                     // OpenGL ES only supports the float varieties of glVertexAttrib
                     GrGLfloat c[4];
                     GrColorToRGBAFloat(color, c);
-                    GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
+                    GL_CALL(VertexAttrib4fv(kColorAttributeIndex, c));
                     sharedState->fConstAttribColor = color;
                 }
                 break;
@@ -1101,7 +1101,7 @@ void GrGLProgram::setCoverage(const GrDrawState& drawState,
                     // OpenGL ES only supports the float varieties of  glVertexAttrib
                     GrGLfloat c[4];
                     GrColorToRGBAFloat(coverage, c);
-                    GL_CALL(VertexAttrib4fv(GrGLProgram::CoverageAttributeIdx(), c));
+                    GL_CALL(VertexAttrib4fv(kCoverageAttributeIndex, c));
                     sharedState->fConstAttribCoverage = coverage;
                 }
                 break;
index 2c3c973c7cee0035e4a721247cc5182444f80ada..2c48d73e0328fe01f2770c2d6f51eb698a17a9fb 100644 (file)
@@ -81,11 +81,13 @@ public:
     /**
      * Attribute indices. These should not overlap.
      */
-    static int PositionAttributeIdx() { return 0; }
-    static int ColorAttributeIdx() { return 1; }
-    static int CoverageAttributeIdx() { return 2; }
-    static int EdgeAttributeIdx() { return 3; }
-    static int TexCoordAttributeIdx() { return 4; }
+    enum {
+        kPositionAttributeIndex = 0,
+        kColorAttributeIndex = 1,
+        kCoverageAttributeIndex = 2,
+        kEdgeAttributeIndex = 3,
+        kTexCoordAttributeIndex = 4,
+    };
 
     /**
      * Some GL state that is relevant to programs is not stored per-program. In particular vertex
index 1512fef1fa3d57c2a2b649438c37ba98b85c6da2..42b76ea4a88df76e2066628a213e51c1c4d03f9e 100644 (file)
@@ -47,10 +47,6 @@ void GrGLVertexBuffer::bind() const {
     GPUGL->notifyVertexBufferBind(this);
 }
 
-GrGLuint GrGLVertexBuffer::bufferID() const {
-    return fBufferID;
-}
-
 void* GrGLVertexBuffer::lock() {
     GrAssert(fBufferID);
     GrAssert(!isLocked());
index 17b0283f102b43f7cbf9770341fd13a293112e56..61b5020404d2531dedb955ded8b20c37f1034914 100644 (file)
@@ -18,34 +18,35 @@ class GrGpuGL;
 class GrGLVertexBuffer : public GrVertexBuffer {
 
 public:
+    GrGLVertexBuffer(GrGpuGL* gpu,
+                     bool isWrapped,
+                     GrGLuint id,
+                     size_t sizeInBytes,
+                     bool dynamic);
     virtual ~GrGLVertexBuffer() { this->release(); }
+
+    GrGLuint bufferID() const { return fBufferID; }
+    size_t baseOffset() const { return 0; }
+
+    void bind() const;
+
     // overrides of GrVertexBuffer
     virtual void* lock();
     virtual void* lockPtr() const;
     virtual void unlock();
     virtual bool isLocked() const;
     virtual bool updateData(const void* src, size_t srcSizeInBytes);
-    GrGLuint bufferID() const;
 
 protected:
-    GrGLVertexBuffer(GrGpuGL* gpu,
-                     bool isWrapped,
-                     GrGLuint id,
-                     size_t sizeInBytes,
-                     bool dynamic);
-
     // overrides of GrResource
     virtual void onAbandon() SK_OVERRIDE;
     virtual void onRelease() SK_OVERRIDE;
 
 private:
-    void bind() const;
 
     GrGLuint     fBufferID;
     void*        fLockPtr;
 
-    friend class GrGpuGL;
-
     typedef GrVertexBuffer INHERITED;
 };
 
index f14238cdd91ecdf7ca773ce60976d7b44fa2b3ff..baa6e44ef2f43d58a25130951b66e91eefeb7df0 100644 (file)
@@ -178,6 +178,8 @@ GrGpuGL::GrGpuGL(const GrGLContextInfo& ctxInfo) : fGLContextInfo(ctxInfo) {
 
     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 @@ void GrGpuGL::onResetContext() {
     fHWStencilSettings.invalidate();
     fHWStencilTestEnabled = kUnknown_TriState;
 
-    fHWGeometryState.fIndexBuffer = NULL;
-    fHWGeometryState.fVertexBuffer = NULL;
-
-    fHWGeometryState.fArrayPtrsDirty = true;
+    fHWGeometryState.invalidate();
 
     fHWBoundRenderTarget = NULL;
 
@@ -474,28 +473,6 @@ void GrGpuGL::onResetContext() {
         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 @@ GrVertexBuffer* GrGpuGL::onCreateVertexBuffer(uint32_t size, bool dynamic) {
     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 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
         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 @@ GrGLenum gPrimitiveType2GLMode[] = {
 #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::flushMiscFixedFunctionState() {
 }
 
 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::setSpareTextureUnit() {
     }
 }
 
-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 @@ void GrGpuGL::setBuffers(bool indexed,
 
         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;
     }
 }
index 505c99c37420bc7a3a16ed9b7b4554c4802e3707..fae4a93c6c8cf9ca50401be90887d2063fab8621 100644 (file)
@@ -57,6 +57,14 @@ public:
 
     const GrGLCaps& glCaps() const { return fGLContextInfo.caps(); }
 
+    // Callbacks to update state tracking when related GL objects are bound or deleted
+    void notifyVertexBufferBind(const GrGLVertexBuffer* buffer);
+    void notifyVertexBufferDelete(const GrGLVertexBuffer* buffer);
+    void notifyIndexBufferBind(const GrGLIndexBuffer* buffer);
+    void notifyIndexBufferDelete(const GrGLIndexBuffer* buffer);
+    void notifyTextureDelete(GrGLTexture* texture);
+    void notifyRenderTargetDelete(GrRenderTarget* renderTarget);
+
 private:
     // GrGpu overrides
     virtual void onResetContext() SK_OVERRIDE;
@@ -112,14 +120,16 @@ private:
     // binds texture unit in GL
     void setTextureUnit(int unitIdx);
 
-    // Sets up vertex attribute pointers and strides. On return startIndexOffset specifies an
-    // offset into the index buffer to the first index to be read (in addition to
-    // info.startIndex()). It accounts for the fact that index buffer pool may have provided space
-    // in the middle of a larger index buffer.
-    void setupGeometry(const DrawInfo& info, int* startIndexOffset);
-    // binds appropriate vertex and index buffers, also returns any extra verts or indices to
-    // offset by based on how space was allocated in pool VB/IBs.
-    void setBuffers(bool indexed, int* extraVertexOffset, int* extraIndexOffset);
+    // Sets up vertex attribute pointers and strides. On return indexOffsetInBytes gives the offset
+    // an into the index buffer. It does not account for drawInfo.startIndex() but rather the start
+    // index is relative to the returned offset.
+    void setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes);
+    // binds appropriate vertex and index buffers. It also returns offsets for the vertex and index
+    // buffers. These offsets account for placement within a pool buffer or CPU-side addresses for
+    // use with buffer 0. They do not account for start values in the DrawInfo (which is not passed
+    // here). The vertex buffer that contains the vertex data is returned. It is not necessarily
+    // bound.
+    GrGLVertexBuffer* setBuffers(bool indexed, size_t* vertexOffsetInBytes, size_t* indexOffsetInBytes);
 
     // Subclasses should call this to flush the blend state.
     // The params should be the final coefficients to apply
@@ -199,15 +209,6 @@ private:
     // determines valid stencil formats
     void initStencilFormats();
 
-    // notify callbacks to update state tracking when related
-    // objects are bound to GL or deleted outside of the class
-    void notifyVertexBufferBind(const GrGLVertexBuffer* buffer);
-    void notifyVertexBufferDelete(const GrGLVertexBuffer* buffer);
-    void notifyIndexBufferBind(const GrGLIndexBuffer* buffer);
-    void notifyIndexBufferDelete(const GrGLIndexBuffer* buffer);
-    void notifyTextureDelete(GrGLTexture* texture);
-    void notifyRenderTargetDelete(GrRenderTarget* renderTarget);
-
     void setSpareTextureUnit();
 
     // bound is region that may be modified and therefore has to be resolved.
@@ -235,11 +236,6 @@ private:
 
     void fillInConfigRenderableTable();
 
-    friend class GrGLVertexBuffer;
-    friend class GrGLIndexBuffer;
-    friend class GrGLTexture;
-    friend class GrGLRenderTarget;
-
     GrGLContextInfo fGLContextInfo;
 
     // GL program-related state
@@ -272,12 +268,139 @@ private:
 
     GrGLIRect   fHWViewport;
 
-    struct {
-        size_t                  fVertexOffset;
-        GrVertexLayout          fVertexLayout;
-        const GrVertexBuffer*   fVertexBuffer;
-        const GrIndexBuffer*    fIndexBuffer;
-        bool                    fArrayPtrsDirty;
+    /**
+     * Tracks bound vertex and index buffers and vertex attrib array state.
+     */
+    class HWGeometryState {
+    public:
+        HWGeometryState() { fAttribArrayCount = 0; this->invalidate();}
+
+        void setMaxAttribArrays(int max) {
+            fAttribArrayCount = max;
+            fAttribArrays.reset(max);
+            for (int i = 0; i < fAttribArrayCount; ++i) {
+                fAttribArrays[i].invalidate();
+            }
+        }
+
+        void invalidate() {
+            fBoundVertexBufferIDIsValid = false;
+            fBoundIndexBufferIDIsValid = false;
+            for (int i = 0; i < fAttribArrayCount; ++i) {
+                fAttribArrays[i].invalidate();
+            }
+        }
+
+        void notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
+            GrGLuint id = buffer->bufferID();
+            if (0 != id) {
+                if (this->isVertexBufferIDBound(id)) {
+                    // deleting bound buffer does implied bind to 0
+                    this->setVertexBufferID(0);
+                }
+                for (int i = 0; i < fAttribArrayCount; ++i) {
+                    if (fAttribArrays[i].vertexBufferID() == id) {
+                        fAttribArrays[i].invalidate();
+                    }
+                }
+            }
+        }
+
+        void notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
+            GrGLuint id = buffer->bufferID();
+            if (0 != id) {
+                if (this->isIndexBufferIDBound(id)) {
+                    // deleting bound buffer does implied bind to 0
+                    this->setIndexBufferID(0);
+                }
+            }
+        }
+
+        void setVertexBufferID(GrGLuint id) {
+            fBoundVertexBufferIDIsValid = true;
+            fBoundVertexBufferID = id;
+        }
+
+        void setIndexBufferID(GrGLuint id) {
+            fBoundIndexBufferIDIsValid = true;
+            fBoundIndexBufferID = id;
+        }
+
+        bool isVertexBufferIDBound(GrGLuint id) const {
+            return fBoundVertexBufferIDIsValid && id == fBoundVertexBufferID;
+        }
+
+        bool isIndexBufferIDBound(GrGLuint id) const {
+            return fBoundIndexBufferIDIsValid && id == fBoundIndexBufferID;
+        }
+
+        void setAttribArray(const GrGpuGL* gpu,
+                            int index,
+                            GrGLVertexBuffer* vertexBuffer,
+                            GrGLint size,
+                            GrGLenum type,
+                            GrGLboolean normalized,
+                            GrGLsizei stride,
+                            GrGLvoid* offset) {
+            GrAssert(index >= 0 && index < fAttribArrayCount);
+            AttribArray* attrib = fAttribArrays.get() + index;
+            attrib->set(gpu, this, index, vertexBuffer, size, type, normalized, stride, offset);
+        }
+
+        void disableUnusedAttribArrays(const GrGpuGL* gpu,
+                                       uint32_t usedAttribIndexMask) {
+            for (int i = 0; i < fAttribArrayCount; ++i) {
+                if (!(usedAttribIndexMask & (1 << i))) {
+                    fAttribArrays[i].disable(gpu, i);
+                }
+            }
+        }
+
+    private:
+        GrGLuint                fBoundVertexBufferID;
+        GrGLuint                fBoundIndexBufferID;
+        bool                    fBoundVertexBufferIDIsValid;
+        bool                    fBoundIndexBufferIDIsValid;
+
+        struct AttribArray {
+        public:
+            void set(const GrGpuGL* gpu,
+                     HWGeometryState* geoState,
+                     int index,
+                     GrGLVertexBuffer* vertexBuffer,
+                     GrGLint size,
+                     GrGLenum type,
+                     GrGLboolean normalized,
+                     GrGLsizei stride,
+                     GrGLvoid* offset);
+
+            void disable(const GrGpuGL* gpu, int index) {
+                if (!fEnableIsValid || fEnabled) {
+                    GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(index));
+                    fEnableIsValid = true;
+                    fEnabled = false;
+                }
+            }
+
+            void invalidate() {
+                fEnableIsValid = false;
+                fAttribPointerIsValid = false;
+            }
+
+            GrGLuint vertexBufferID() const { return fVertexBufferID; }
+        private:
+            bool        fEnableIsValid;
+            bool        fAttribPointerIsValid;
+            bool        fEnabled;
+            GrGLuint    fVertexBufferID;
+            GrGLint     fSize;
+            GrGLenum    fType;
+            GrGLboolean fNormalized;
+            GrGLsizei   fStride;
+            GrGLvoid*   fOffset;
+        };
+        SkAutoTArray<AttribArray> fAttribArrays;
+        int                       fAttribArrayCount;
     } fHWGeometryState;
 
     struct {
index 84e3b6dbfde4c659abae4c19b67f94ebc23c37d6..87b0893bbed84b260ce08b25e5b7a569ceef42f8 100644 (file)
@@ -213,103 +213,85 @@ bool GrGpuGL::flushGraphicsState(DrawType type) {
     return true;
 }
 
-void GrGpuGL::setupGeometry(const DrawInfo& info, int* startIndexOffset) {
+void GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) {
 
-    int newColorOffset;
-    int newCoverageOffset;
-    int newTexCoordOffset;
-    int newEdgeOffset;
+    int colorOffset;
+    int coverageOffset;
+    int texCoordOffset;
+    int edgeOffset;
 
     GrVertexLayout currLayout = this->getDrawState().getVertexLayout();
 
-    GrGLsizei newStride = GrDrawState::VertexSizeAndOffsets(currLayout,
-                                                            &newTexCoordOffset,
-                                                            &newColorOffset,
-                                                            &newCoverageOffset,
-                                                            &newEdgeOffset);
-    int oldColorOffset;
-    int oldCoverageOffset;
-    int oldTexCoordOffset;
-    int oldEdgeOffset;
-
-    GrGLsizei oldStride = GrDrawState::VertexSizeAndOffsets(fHWGeometryState.fVertexLayout,
-                                                            &oldTexCoordOffset,
-                                                            &oldColorOffset,
-                                                            &oldCoverageOffset,
-                                                            &oldEdgeOffset);
-
-    int extraVertexOffset;
-    this->setBuffers(info.isIndexed(), &extraVertexOffset, startIndexOffset);
-
-    size_t vertexOffset = (info.startVertex() + extraVertexOffset) * newStride;
-
-    // all the Pointers must be set if any of these are true
-    bool allOffsetsChange =  fHWGeometryState.fArrayPtrsDirty ||
-                             vertexOffset != fHWGeometryState.fVertexOffset ||
-                             newStride != oldStride;
-
-    if (allOffsetsChange) {
-        int idx = GrGLProgram::PositionAttributeIdx();
-        GL_CALL(VertexAttribPointer(idx, 2, GR_GL_FLOAT, false, newStride, (GrGLvoid*)vertexOffset));
-        fHWGeometryState.fVertexOffset = vertexOffset;
+    GrGLsizei stride = GrDrawState::VertexSizeAndOffsets(currLayout,
+                                                         &texCoordOffset,
+                                                         &colorOffset,
+                                                         &coverageOffset,
+                                                         &edgeOffset);
+
+    size_t vertexOffset;
+    GrGLVertexBuffer* vb= this->setBuffers(info.isIndexed(), &vertexOffset, indexOffsetInBytes);
+    vertexOffset += stride * info.startVertex();
+
+    uint32_t usedAttribArraysMask = (1 << GrGLProgram::kPositionAttributeIndex);
+    fHWGeometryState.setAttribArray(this,
+                                    GrGLProgram::kPositionAttributeIndex,
+                                    vb,
+                                    2,
+                                    GR_GL_FLOAT,
+                                    false,
+                                    stride,
+                                    reinterpret_cast<GrGLvoid*>(vertexOffset));
+    if (texCoordOffset > 0) {
+        usedAttribArraysMask |= (1 << GrGLProgram::kTexCoordAttributeIndex);
+        GrGLvoid* texCoordPtr = reinterpret_cast<GrGLvoid*>(vertexOffset + texCoordOffset);
+        fHWGeometryState.setAttribArray(this,
+                                        GrGLProgram::kTexCoordAttributeIndex,
+                                        vb,
+                                        2,
+                                        GR_GL_FLOAT,
+                                        false,
+                                        stride,
+                                        texCoordPtr);
     }
 
-    if (newTexCoordOffset > 0) {
-        GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffset);
-        int idx = GrGLProgram::TexCoordAttributeIdx();
-        if (oldTexCoordOffset <= 0) {
-            GL_CALL(EnableVertexAttribArray(idx));
-            GL_CALL(VertexAttribPointer(idx, 2, GR_GL_FLOAT, false, newStride, texCoordOffset));
-        } else if (allOffsetsChange || newTexCoordOffset != oldTexCoordOffset) {
-            GL_CALL(VertexAttribPointer(idx, 2, GR_GL_FLOAT, false, newStride, texCoordOffset));
-        }
-    } else if (oldTexCoordOffset > 0) {
-        GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx()));
-    }
-
-    if (newColorOffset > 0) {
-        fSharedGLProgramState.fConstAttribColor = GrColor_ILLEGAL;
-        GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
-        int idx = GrGLProgram::ColorAttributeIdx();
-        if (oldColorOffset <= 0) {
-            GL_CALL(EnableVertexAttribArray(idx));
-            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, true, newStride, colorOffset));
-        } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
-            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, true, newStride, colorOffset));
-        }
-    } else if (oldColorOffset > 0) {
-        GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
+    if (colorOffset > 0) {
+        usedAttribArraysMask |= (1 << GrGLProgram::kColorAttributeIndex);
+        GrGLvoid* colorPtr = reinterpret_cast<GrGLvoid*>(vertexOffset + colorOffset);
+        fHWGeometryState.setAttribArray(this,
+                                        GrGLProgram::kColorAttributeIndex,
+                                        vb,
+                                        4,
+                                        GR_GL_UNSIGNED_BYTE,
+                                        true,
+                                        stride,
+                                        colorPtr);
     }
 
-    if (newCoverageOffset > 0) {
-        fSharedGLProgramState.fConstAttribColor = GrColor_ILLEGAL;
-        GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset);
-        int idx = GrGLProgram::CoverageAttributeIdx();
-        if (oldCoverageOffset <= 0) {
-            GL_CALL(EnableVertexAttribArray(idx));
-            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
-                                        true, newStride, coverageOffset));
-        } else if (allOffsetsChange || newCoverageOffset != oldCoverageOffset) {
-            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
-                                        true, newStride, coverageOffset));
-        }
-    } else if (oldCoverageOffset > 0) {
-        GL_CALL(DisableVertexAttribArray(GrGLProgram::CoverageAttributeIdx()));
+    if (coverageOffset > 0) {
+        usedAttribArraysMask |= (1 << GrGLProgram::kCoverageAttributeIndex);
+        GrGLvoid* coveragePtr = reinterpret_cast<GrGLvoid*>(vertexOffset + coverageOffset);
+        fHWGeometryState.setAttribArray(this,
+                                        GrGLProgram::kCoverageAttributeIndex,
+                                        vb,
+                                        4,
+                                        GR_GL_UNSIGNED_BYTE,
+                                        true,
+                                        stride,
+                                        coveragePtr);
     }
 
-    if (newEdgeOffset > 0) {
-        GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset);
-        int idx = GrGLProgram::EdgeAttributeIdx();
-        if (oldEdgeOffset <= 0) {
-            GL_CALL(EnableVertexAttribArray(idx));
-            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_FLOAT, false, newStride, edgeOffset));
-        } else if (allOffsetsChange || newEdgeOffset != oldEdgeOffset) {
-            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_FLOAT, false, newStride, edgeOffset));
-        }
-    } else if (oldEdgeOffset > 0) {
-        GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx()));
+    if (edgeOffset > 0) {
+        usedAttribArraysMask |= (1 << GrGLProgram::kEdgeAttributeIndex);
+        GrGLvoid* edgePtr = reinterpret_cast<GrGLvoid*>(vertexOffset + edgeOffset);
+        fHWGeometryState.setAttribArray(this,
+                                        GrGLProgram::kEdgeAttributeIndex,
+                                        vb,
+                                        4,
+                                        GR_GL_FLOAT,
+                                        false,
+                                        stride,
+                                        edgePtr);
     }
 
-    fHWGeometryState.fVertexLayout = currLayout;
-    fHWGeometryState.fArrayPtrsDirty = false;
+    fHWGeometryState.disableUnusedAttribArrays(this, usedAttribArraysMask);
 }