1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 9 10 #include "GrGLIndexBuffer.h" 11 #include "GrGpuGL.h" 12 13 #define GPUGL static_cast<GrGpuGL*>(getGpu()) 14 15 #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X) 16 17 GrGLIndexBuffer::GrGLIndexBuffer(GrGpuGL* gpu, 18 bool isWrapped, 19 GrGLuint id, 20 size_t sizeInBytes, 21 bool dynamic) 22 : INHERITED(gpu, isWrapped, sizeInBytes, dynamic) 23 , fBufferID(id) 24 , fLockPtr(NULL) { 25 26 } 27 28 void GrGLIndexBuffer::onRelease() { 29 // make sure we've not been abandoned 30 if (fBufferID && !this->isWrapped()) { 31 GPUGL->notifyIndexBufferDelete(this); 32 GL_CALL(DeleteBuffers(1, &fBufferID)); 33 fBufferID = 0; 34 } 35 36 INHERITED::onRelease(); 37 } 38 39 void GrGLIndexBuffer::onAbandon() { 40 fBufferID = 0; 41 fLockPtr = NULL; 42 43 INHERITED::onAbandon(); 44 } 45 46 void GrGLIndexBuffer::bind() const { 47 GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, fBufferID)); 48 GPUGL->notifyIndexBufferBind(this); 49 } 50 51 GrGLuint GrGLIndexBuffer::bufferID() const { 52 return fBufferID; 53 } 54 55 void* GrGLIndexBuffer::lock() { 56 GrAssert(fBufferID); 57 GrAssert(!isLocked()); 58 if (this->getGpu()->getCaps().bufferLockSupport()) { 59 this->bind(); 60 // Let driver know it can discard the old data 61 GL_CALL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, 62 this->sizeInBytes(), 63 NULL, 64 this->dynamic() ? GR_GL_DYNAMIC_DRAW : 65 GR_GL_STATIC_DRAW)); 66 GR_GL_CALL_RET(GPUGL->glInterface(), 67 fLockPtr, 68 MapBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 69 GR_GL_WRITE_ONLY)); 70 71 return fLockPtr; 72 } 73 return NULL; 74 } 75 76 void* GrGLIndexBuffer::lockPtr() const { 77 return fLockPtr; 78 } 79 80 void GrGLIndexBuffer::unlock() { 81 GrAssert(fBufferID); 82 GrAssert(isLocked()); 83 GrAssert(this->getGpu()->getCaps().bufferLockSupport()); 84 85 this->bind(); 86 GL_CALL(UnmapBuffer(GR_GL_ELEMENT_ARRAY_BUFFER)); 87 fLockPtr = NULL; 88 } 89 90 bool GrGLIndexBuffer::isLocked() const { 91 // this check causes a lot of noise in the gl log 92 #if 0 93 if (this->isValid() && this->getGpu()->getCaps().fBufferLockSupport) { 94 this->bind(); 95 GrGLint mapped; 96 GL_CALL(GetBufferParameteriv(GR_GL_ELEMENT_ARRAY_BUFFER, 97 GR_GL_BUFFER_MAPPED, &mapped)); 98 GrAssert(!!mapped == !!fLockPtr); 99 } 100 #endif 101 return NULL != fLockPtr; 102 } 103 104 bool GrGLIndexBuffer::updateData(const void* src, size_t srcSizeInBytes) { 105 GrAssert(fBufferID); 106 GrAssert(!isLocked()); 107 if (srcSizeInBytes > this->sizeInBytes()) { 108 return false; 109 } 110 this->bind(); 111 GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW; 112 113 #if GR_GL_USE_BUFFER_DATA_NULL_HINT 114 if (this->sizeInBytes() == srcSizeInBytes) { 115 GL_CALL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, 116 srcSizeInBytes, src, usage)); 117 } else { 118 // Before we call glBufferSubData we give the driver a hint using 119 // glBufferData with NULL. This makes the old buffer contents 120 // inaccessible to future draws. The GPU may still be processing 121 // draws that reference the old contents. With this hint it can 122 // assign a different allocation for the new contents to avoid 123 // flushing the gpu past draws consuming the old contents. 124 GL_CALL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, 125 this->sizeInBytes(), NULL, usage)); 126 GL_CALL(BufferSubData(GR_GL_ELEMENT_ARRAY_BUFFER, 127 0, srcSizeInBytes, src)); 128 } 129 #else 130 // Note that we're cheating on the size here. Currently no methods 131 // allow a partial update that preserves contents of non-updated 132 // portions of the buffer (lock() does a glBufferData(..size, NULL..)) 133 GL_CALL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, 134 srcSizeInBytes, src, usage)); 135 #endif 136 return true; 137 } 138