• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 
11 #include "GrGLVertexBuffer.h"
12 #include "GrGpuGL.h"
13 
14 #define GPUGL static_cast<GrGpuGL*>(getGpu())
15 
16 #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
17 
GrGLVertexBuffer(GrGpuGL * gpu,GrGLuint id,size_t sizeInBytes,bool dynamic)18 GrGLVertexBuffer::GrGLVertexBuffer(GrGpuGL* gpu,
19                                    GrGLuint id,
20                                    size_t sizeInBytes,
21                                    bool dynamic)
22     : INHERITED(gpu, 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) {
30         GPUGL->notifyVertexBufferDelete(this);
31         GL_CALL(DeleteBuffers(1, &fBufferID));
32         fBufferID = 0;
33     }
34 }
35 
onAbandon()36 void GrGLVertexBuffer::onAbandon() {
37     fBufferID = 0;
38     fLockPtr = NULL;
39 }
40 
bind() const41 void GrGLVertexBuffer::bind() const {
42     GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, fBufferID));
43     GPUGL->notifyVertexBufferBind(this);
44 }
45 
bufferID() const46 GrGLuint GrGLVertexBuffer::bufferID() const {
47     return fBufferID;
48 }
49 
lock()50 void* GrGLVertexBuffer::lock() {
51     GrAssert(fBufferID);
52     GrAssert(!isLocked());
53     if (this->getGpu()->getCaps().fBufferLockSupport) {
54         this->bind();
55         // Let driver know it can discard the old data
56         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, this->sizeInBytes(), NULL,
57                            this->dynamic() ? GR_GL_DYNAMIC_DRAW :
58                                              GR_GL_STATIC_DRAW));
59         GR_GL_CALL_RET(GPUGL->glInterface(),
60                        fLockPtr,
61                        MapBuffer(GR_GL_ARRAY_BUFFER, GR_GL_WRITE_ONLY));
62         return fLockPtr;
63     }
64     return NULL;
65 }
66 
lockPtr() const67 void* GrGLVertexBuffer::lockPtr() const {
68     return fLockPtr;
69 }
70 
unlock()71 void GrGLVertexBuffer::unlock() {
72 
73     GrAssert(fBufferID);
74     GrAssert(isLocked());
75     GrAssert(this->getGpu()->getCaps().fBufferLockSupport);
76 
77     this->bind();
78     GL_CALL(UnmapBuffer(GR_GL_ARRAY_BUFFER));
79     fLockPtr = NULL;
80 }
81 
isLocked() const82 bool GrGLVertexBuffer::isLocked() const {
83     GrAssert(!this->isValid() || fBufferID);
84 #if GR_DEBUG
85     if (this->isValid() && this->getGpu()->getCaps().fBufferLockSupport) {
86         GrGLint mapped;
87         this->bind();
88         GL_CALL(GetBufferParameteriv(GR_GL_ARRAY_BUFFER,
89                                      GR_GL_BUFFER_MAPPED, &mapped));
90         GrAssert(!!mapped == !!fLockPtr);
91     }
92 #endif
93     return NULL != fLockPtr;
94 }
95 
updateData(const void * src,size_t srcSizeInBytes)96 bool GrGLVertexBuffer::updateData(const void* src, size_t srcSizeInBytes) {
97     GrAssert(fBufferID);
98     GrAssert(!isLocked());
99     if (srcSizeInBytes > this->sizeInBytes()) {
100         return false;
101     }
102     this->bind();
103     GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
104 
105 #if GR_GL_USE_BUFFER_DATA_NULL_HINT
106     if (this->sizeInBytes() == srcSizeInBytes) {
107         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
108     } else {
109         // Before we call glBufferSubData we give the driver a hint using
110         // glBufferData with NULL. This makes the old buffer contents
111         // inaccessible to future draws. The GPU may still be processing
112         // draws that reference the old contents. With this hint it can
113         // assign a different allocation for the new contents to avoid
114         // flushing the gpu past draws consuming the old contents.
115         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER,
116                            this->sizeInBytes(), NULL, usage));
117         GL_CALL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src));
118     }
119 #else
120     // Note that we're cheating on the size here. Currently no methods
121     // allow a partial update that preserves contents of non-updated
122     // portions of the buffer (lock() does a glBufferData(..size, NULL..))
123     bool doSubData = false;
124 #if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND
125     static int N = 0;
126     // 128 was chosen experimentally. At 256 a slight hitchiness was noticed
127     // when dragging a Chromium window around with a canvas tab backgrounded.
128     doSubData = 0 == (N % 128);
129     ++N;
130 #endif
131     if (doSubData) {
132         // The workaround is to do a glBufferData followed by glBufferSubData.
133         // Chromium's command buffer may turn a glBufferSubData where the size
134         // exactly matches the buffer size into a glBufferData. So we tack 1
135         // extra byte onto the glBufferData.
136         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes + 1,
137                            NULL, usage));
138         GL_CALL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src));
139     } else {
140         GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
141     }
142 #endif
143     return true;
144 }
145 
146