Chromium Code Reviews| Index: src/gpu/gl/GrGpuGL.h | 
| =================================================================== | 
| --- src/gpu/gl/GrGpuGL.h (revision 8015) | 
| +++ src/gpu/gl/GrGpuGL.h (working copy) | 
| @@ -20,6 +20,7 @@ | 
| #include "GrGLProgram.h" | 
| #include "GrGLStencilBuffer.h" | 
| #include "GrGLTexture.h" | 
| +#include "GrGLVertexArray.h" | 
| #include "GrGLVertexBuffer.h" | 
| #include "../GrTHashCache.h" | 
| @@ -54,11 +55,29 @@ | 
| const GrGLCaps& glCaps() const { return fGLContext.info().caps(); } | 
| - // Callbacks to update state tracking when related GL objects are bound or deleted | 
| - void notifyVertexBufferBind(GrGLuint id); | 
| - void notifyVertexBufferDelete(GrGLuint id); | 
| - void notifyIndexBufferBind(GrGLuint id); | 
| - void notifyIndexBufferDelete(GrGLuint id); | 
| + // These functions should be used to bind GL objects. They track the GL state and skip redundant | 
| + // bindings. Making the equivalent glBind calls directly will confuse the state tracking. | 
| + void bindVertexArray(GrGLuint id) { | 
| + fHWGeometryState.setVertexArrayID(this, id); | 
| + } | 
| + void bindIndexBufferAndDefaultVertexArray(GrGLuint id) { | 
| + fHWGeometryState.setIndexBufferIDOnDefaultVertexArray(this, id); | 
| + } | 
| + void bindVertexBuffer(GrGLuint id) { | 
| + fHWGeometryState.setVertexBufferID(this, id); | 
| + } | 
| + | 
| + // These callbacks update state tracking when GL objects are deleted. They are called from | 
| + // GrGLResource onRelease functions. | 
| + void notifyVertexBufferDelete(GrGLuint id) { | 
| + fHWGeometryState.notifyVertexBufferDelete(id); | 
| + } | 
| + void notifyIndexBufferDelete(GrGLuint id) { | 
| + fHWGeometryState.notifyIndexBufferDelete(id); | 
| + } | 
| + void notifyVertexArrayDelete(GrGLuint id) { | 
| 
 
jvanverth1
2013/03/07 16:17:44
Match the order of the notify*Delete methods with
 
bsalomon
2013/03/07 16:25:07
will do before landing.
 
 | 
| + fHWGeometryState.notifyVertexArrayDelete(id); | 
| + } | 
| void notifyTextureDelete(GrGLTexture* texture); | 
| void notifyRenderTargetDelete(GrRenderTarget* renderTarget); | 
| @@ -121,12 +140,6 @@ | 
| // 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 | 
| @@ -268,134 +281,104 @@ | 
| */ | 
| class HWGeometryState { | 
| public: | 
| - HWGeometryState() { fAttribArrayCount = 0; this->invalidate();} | 
| + HWGeometryState() { fVBOVertexArray = NULL; this->invalidate(); } | 
| + | 
| + ~HWGeometryState() { SkSafeUnref(fVBOVertexArray); } | 
| - void setMaxAttribArrays(int max) { | 
| - fAttribArrayCount = max; | 
| - fAttribArrays.reset(max); | 
| - for (int i = 0; i < fAttribArrayCount; ++i) { | 
| - fAttribArrays[i].invalidate(); | 
| + void invalidate() { | 
| + fBoundVertexArrayIDIsValid = false; | 
| + fBoundVertexBufferIDIsValid = false; | 
| + fDefaultVertexArrayBoundIndexBufferID = false; | 
| + fDefaultVertexArrayBoundIndexBufferIDIsValid = false; | 
| + fDefaultVertexArrayAttribState.invalidate(); | 
| + } | 
| + | 
| + void notifyVertexArrayDelete(GrGLuint id) { | 
| + if (fBoundVertexArrayIDIsValid && fBoundVertexArrayID == id) { | 
| + // Does implicit bind to 0 | 
| + fBoundVertexArrayID = 0; | 
| } | 
| } | 
| - void invalidate() { | 
| - fBoundVertexBufferIDIsValid = false; | 
| - fBoundIndexBufferIDIsValid = false; | 
| - for (int i = 0; i < fAttribArrayCount; ++i) { | 
| - fAttribArrays[i].invalidate(); | 
| + void setVertexArrayID(GrGpuGL* gpu, GrGLuint arrayID) { | 
| + if (!gpu->glCaps().vertexArrayObjectSupport()) { | 
| + GrAssert(0 == arrayID); | 
| + return; | 
| } | 
| + if (!fBoundVertexArrayIDIsValid || arrayID != fBoundVertexArrayID) { | 
| + GR_GL_CALL(gpu->glInterface(), BindVertexArray(arrayID)); | 
| + fBoundVertexArrayIDIsValid = true; | 
| + fBoundVertexArrayID = arrayID; | 
| + } | 
| } | 
| void notifyVertexBufferDelete(GrGLuint id) { | 
| - 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].isVertexBufferIDBound(id)) { | 
| - fAttribArrays[i].invalidate(); | 
| - } | 
| - } | 
| + if (fBoundVertexBufferIDIsValid && id == fBoundVertexBufferID) { | 
| + fBoundVertexBufferID = 0; | 
| } | 
| + if (NULL != fVBOVertexArray) { | 
| + fVBOVertexArray->notifyVertexBufferDelete(id); | 
| + } | 
| + fDefaultVertexArrayAttribState.notifyVertexBufferDelete(id); | 
| } | 
| void notifyIndexBufferDelete(GrGLuint id) { | 
| - if (0 != id) { | 
| - if (this->isIndexBufferIDBound(id)) { | 
| - // deleting bound buffer does implied bind to 0 | 
| - this->setIndexBufferID(0); | 
| - } | 
| + if (fDefaultVertexArrayBoundIndexBufferIDIsValid && | 
| + id == fDefaultVertexArrayBoundIndexBufferID) { | 
| + fDefaultVertexArrayBoundIndexBufferID = 0; | 
| } | 
| + if (NULL != fVBOVertexArray) { | 
| + fVBOVertexArray->notifyIndexBufferDelete(id); | 
| + } | 
| } | 
| - void setVertexBufferID(GrGLuint id) { | 
| - fBoundVertexBufferIDIsValid = true; | 
| - fBoundVertexBufferID = id; | 
| + void setVertexBufferID(GrGpuGL* gpu, GrGLuint id) { | 
| + if (!fBoundVertexBufferIDIsValid || id != fBoundVertexBufferID) { | 
| + GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ARRAY_BUFFER, 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); | 
| - } | 
| + /** | 
| + * Binds the default vertex array and binds the index buffer. This is used when binding | 
| + * an index buffer in order to update it. | 
| + */ | 
| + void setIndexBufferIDOnDefaultVertexArray(GrGpuGL* gpu, GrGLuint id) { | 
| + this->setVertexArrayID(gpu, 0); | 
| + if (!fDefaultVertexArrayBoundIndexBufferIDIsValid || | 
| + id != fDefaultVertexArrayBoundIndexBufferID) { | 
| + GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, id)); | 
| + fDefaultVertexArrayBoundIndexBufferIDIsValid = true; | 
| + fDefaultVertexArrayBoundIndexBufferID = id; | 
| } | 
| } | 
| + /** | 
| + * Binds the vertex array object that should be used to render from the vertex buffer. | 
| + * The vertex array is bound and its attrib array state object is returned. The vertex | 
| + * buffer is bound. The index buffer (if non-NULL) is bound to the vertex array. The | 
| + * returned GrGLAttribArrayState should be used to set vertex attribute arrays. | 
| + */ | 
| + GrGLAttribArrayState* bindArrayAndBuffersToDraw(GrGpuGL* gpu, | 
| + const GrGLVertexBuffer* vbuffer, | 
| + const GrGLIndexBuffer* ibuffer); | 
| + | 
| private: | 
| + GrGLuint fBoundVertexArrayID; | 
| GrGLuint fBoundVertexBufferID; | 
| - GrGLuint fBoundIndexBufferID; | 
| + bool fBoundVertexArrayIDIsValid; | 
| 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); | 
| + GrGLuint fDefaultVertexArrayBoundIndexBufferID; | 
| + bool fDefaultVertexArrayBoundIndexBufferIDIsValid; | 
| + // We return a non-const pointer to this from bindArrayAndBuffersToDraw when vertex array 0 | 
| + // is bound. However, this class is internal to GrGpuGL and this object never leaks out of | 
| + // GrGpuGL. | 
| + GrGLAttribArrayState fDefaultVertexArrayAttribState; | 
| - 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; | 
| - } | 
| - | 
| - bool isVertexBufferIDBound(GrGLuint id) const { | 
| - return fAttribPointerIsValid && id == 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; | 
| + // This is used when we're using a core profile and the vertices are in a VBO. | 
| + GrGLVertexArray* fVBOVertexArray; | 
| } fHWGeometryState; | 
| struct { |