• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrGLVertexBuffer.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 
GrGLVertexBuffer(GrGpuGL * gpu,bool isWrapped,GrGLuint id,size_t sizeInBytes,bool dynamic)17 GrGLVertexBuffer::GrGLVertexBuffer(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 
onRelease()27 void GrGLVertexBuffer::onRelease() {
28     // make sure we've not been abandoned
29     if (fBufferID && !this->isWrapped()) {
30         GPUGL->notifyVertexBufferDelete(this);
31         GL_CALL(DeleteBuffers(1, &fBufferID));
32         fBufferID = 0;
33     }
34 
35     INHERITED::onRelease();
36 }
37 
onAbandon()38 void GrGLVertexBuffer::onAbandon() {
39     fBufferID = 0;
40     fLockPtr = NULL;
41 
42     INHERITED::onAbandon();
43 }
44 
bind() const45 void GrGLVertexBuffer::bind() const {
46     GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, fBufferID));
47     GPUGL->notifyVertexBufferBind(this);
48 }
49 
bufferID() const50 GrGLuint GrGLVertexBuffer::bufferID() const {
51     return fBufferID;
52 }
53 
lock()54 void* GrGLVertexBuffer::lock() {
55     GrAssert(fBufferID);
56     GrAssert(!isLocked());
57     if (this->getGpu()->getCaps().bufferLockSupport()) {
58         this->bind();
59         // Let driver know it can discard the old data
60         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, this->sizeInBytes(), NULL,
61                            this->dynamic() ? GR_GL_DYNAMIC_DRAW :
62                                              GR_GL_STATIC_DRAW));
63         GR_GL_CALL_RET(GPUGL->glInterface(),
64                        fLockPtr,
65                        MapBuffer(GR_GL_ARRAY_BUFFER, GR_GL_WRITE_ONLY));
66         return fLockPtr;
67     }
68     return NULL;
69 }
70 
lockPtr() const71 void* GrGLVertexBuffer::lockPtr() const {
72     return fLockPtr;
73 }
74 
unlock()75 void GrGLVertexBuffer::unlock() {
76 
77     GrAssert(fBufferID);
78     GrAssert(isLocked());
79     GrAssert(this->getGpu()->getCaps().bufferLockSupport());
80 
81     this->bind();
82     GL_CALL(UnmapBuffer(GR_GL_ARRAY_BUFFER));
83     fLockPtr = NULL;
84 }
85 
isLocked() const86 bool GrGLVertexBuffer::isLocked() const {
87     GrAssert(!this->isValid() || fBufferID);
88     // this check causes a lot of noise in the gl log
89 #if 0
90     if (this->isValid() && this->getGpu()->getCaps().fBufferLockSupport) {
91         GrGLint mapped;
92         this->bind();
93         GL_CALL(GetBufferParameteriv(GR_GL_ARRAY_BUFFER,
94                                      GR_GL_BUFFER_MAPPED, &mapped));
95         GrAssert(!!mapped == !!fLockPtr);
96     }
97 #endif
98     return NULL != fLockPtr;
99 }
100 
updateData(const void * src,size_t srcSizeInBytes)101 bool GrGLVertexBuffer::updateData(const void* src, size_t srcSizeInBytes) {
102     GrAssert(fBufferID);
103     GrAssert(!isLocked());
104     if (srcSizeInBytes > this->sizeInBytes()) {
105         return false;
106     }
107     this->bind();
108     GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
109 
110 #if GR_GL_USE_BUFFER_DATA_NULL_HINT
111     if (this->sizeInBytes() == srcSizeInBytes) {
112         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
113     } else {
114         // Before we call glBufferSubData we give the driver a hint using
115         // glBufferData with NULL. This makes the old buffer contents
116         // inaccessible to future draws. The GPU may still be processing
117         // draws that reference the old contents. With this hint it can
118         // assign a different allocation for the new contents to avoid
119         // flushing the gpu past draws consuming the old contents.
120         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER,
121                            this->sizeInBytes(), NULL, usage));
122         GL_CALL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src));
123     }
124 #else
125     // Note that we're cheating on the size here. Currently no methods
126     // allow a partial update that preserves contents of non-updated
127     // portions of the buffer (lock() does a glBufferData(..size, NULL..))
128     bool doSubData = false;
129 #if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND
130     static int N = 0;
131     // 128 was chosen experimentally. At 256 a slight hitchiness was noticed
132     // when dragging a Chromium window around with a canvas tab backgrounded.
133     doSubData = 0 == (N % 128);
134     ++N;
135 #endif
136     if (doSubData) {
137         // The workaround is to do a glBufferData followed by glBufferSubData.
138         // Chromium's command buffer may turn a glBufferSubData where the size
139         // exactly matches the buffer size into a glBufferData. So we tack 1
140         // extra byte onto the glBufferData.
141         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes + 1,
142                            NULL, usage));
143         GL_CALL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src));
144     } else {
145         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
146     }
147 #endif
148     return true;
149 }
150