blob: d932f11b71392034c91581f32d8793e77177eafc [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00006 */
7
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@google.comac10a2d2010-12-22 21:39:39 +000010#include "GrGLVertexBuffer.h"
11#include "GrGpuGL.h"
12
bsalomon@google.com8fe72472011-03-30 21:26:44 +000013#define GPUGL static_cast<GrGpuGL*>(getGpu())
14
bsalomon@google.com0b77d682011-08-19 13:28:54 +000015#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
16
bsalomon@google.com8fe72472011-03-30 21:26:44 +000017GrGLVertexBuffer::GrGLVertexBuffer(GrGpuGL* gpu,
18 GrGLuint id,
19 size_t sizeInBytes,
20 bool dynamic)
21 : INHERITED(gpu, sizeInBytes, dynamic)
22 , fBufferID(id)
23 , fLockPtr(NULL) {
reed@google.comac10a2d2010-12-22 21:39:39 +000024}
25
bsalomon@google.com8fe72472011-03-30 21:26:44 +000026void GrGLVertexBuffer::onRelease() {
reed@google.comac10a2d2010-12-22 21:39:39 +000027 // make sure we've not been abandoned
28 if (fBufferID) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000029 GPUGL->notifyVertexBufferDelete(this);
bsalomon@google.com0b77d682011-08-19 13:28:54 +000030 GL_CALL(DeleteBuffers(1, &fBufferID));
bsalomon@google.com8fe72472011-03-30 21:26:44 +000031 fBufferID = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +000032 }
33}
34
bsalomon@google.com8fe72472011-03-30 21:26:44 +000035void GrGLVertexBuffer::onAbandon() {
36 fBufferID = 0;
37 fLockPtr = NULL;
38}
39
bsalomon@google.com1c13c962011-02-14 16:51:21 +000040void GrGLVertexBuffer::bind() const {
bsalomon@google.com0b77d682011-08-19 13:28:54 +000041 GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, fBufferID));
bsalomon@google.com8fe72472011-03-30 21:26:44 +000042 GPUGL->notifyVertexBufferBind(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +000043}
44
twiz@google.com0f31ca72011-03-18 17:38:11 +000045GrGLuint GrGLVertexBuffer::bufferID() const {
reed@google.comac10a2d2010-12-22 21:39:39 +000046 return fBufferID;
47}
48
reed@google.comac10a2d2010-12-22 21:39:39 +000049void* GrGLVertexBuffer::lock() {
50 GrAssert(fBufferID);
51 GrAssert(!isLocked());
bsalomon@google.com18c9c192011-09-22 21:01:31 +000052 if (this->getGpu()->getCaps().fBufferLockSupport) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000053 this->bind();
bsalomon@google.com1c13c962011-02-14 16:51:21 +000054 // Let driver know it can discard the old data
bsalomon@google.com0b77d682011-08-19 13:28:54 +000055 GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, this->sizeInBytes(), NULL,
56 this->dynamic() ? GR_GL_DYNAMIC_DRAW :
57 GR_GL_STATIC_DRAW));
bsalomon@google.com56bfc5a2011-09-01 13:28:16 +000058 GR_GL_CALL_RET(GPUGL->glInterface(),
59 fLockPtr,
60 MapBuffer(GR_GL_ARRAY_BUFFER, GR_GL_WRITE_ONLY));
reed@google.comac10a2d2010-12-22 21:39:39 +000061 return fLockPtr;
62 }
63 return NULL;
64}
65
bsalomon@google.com1c13c962011-02-14 16:51:21 +000066void* GrGLVertexBuffer::lockPtr() const {
67 return fLockPtr;
68}
69
reed@google.comac10a2d2010-12-22 21:39:39 +000070void GrGLVertexBuffer::unlock() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000071
reed@google.comac10a2d2010-12-22 21:39:39 +000072 GrAssert(fBufferID);
73 GrAssert(isLocked());
bsalomon@google.com18c9c192011-09-22 21:01:31 +000074 GrAssert(this->getGpu()->getCaps().fBufferLockSupport);
bsalomon@google.com1c13c962011-02-14 16:51:21 +000075
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076 this->bind();
bsalomon@google.com0b77d682011-08-19 13:28:54 +000077 GL_CALL(UnmapBuffer(GR_GL_ARRAY_BUFFER));
bsalomon@google.com1c13c962011-02-14 16:51:21 +000078 fLockPtr = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000079}
80
81bool GrGLVertexBuffer::isLocked() const {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000082 GrAssert(!this->isValid() || fBufferID);
bsalomon@google.comd850c182012-03-08 16:45:22 +000083 // this check causes a lot of noise in the gl log
84#if 0
bsalomon@google.com18c9c192011-09-22 21:01:31 +000085 if (this->isValid() && this->getGpu()->getCaps().fBufferLockSupport) {
twiz@google.com0f31ca72011-03-18 17:38:11 +000086 GrGLint mapped;
bsalomon@google.com8fe72472011-03-30 21:26:44 +000087 this->bind();
bsalomon@google.com0b77d682011-08-19 13:28:54 +000088 GL_CALL(GetBufferParameteriv(GR_GL_ARRAY_BUFFER,
89 GR_GL_BUFFER_MAPPED, &mapped));
reed@google.comac10a2d2010-12-22 21:39:39 +000090 GrAssert(!!mapped == !!fLockPtr);
91 }
92#endif
93 return NULL != fLockPtr;
94}
95
bsalomon@google.com1c13c962011-02-14 16:51:21 +000096bool GrGLVertexBuffer::updateData(const void* src, size_t srcSizeInBytes) {
reed@google.comac10a2d2010-12-22 21:39:39 +000097 GrAssert(fBufferID);
98 GrAssert(!isLocked());
bsalomon@google.comcee661a2011-07-26 12:32:36 +000099 if (srcSizeInBytes > this->sizeInBytes()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000100 return false;
101 }
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102 this->bind();
twiz@google.com0f31ca72011-03-18 17:38:11 +0000103 GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
bsalomon@google.com5ffd5ba2012-03-01 15:29:07 +0000104
bsalomon@google.comc1dd8882012-03-02 20:36:18 +0000105#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;
bsalomon@google.com5ffd5ba2012-03-01 15:29:07 +0000124#if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND
bsalomon@google.com5ffd5ba2012-03-01 15:29:07 +0000125 static int N = 0;
bsalomon@google.comc1dd8882012-03-02 20:36:18 +0000126 // 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);
bsalomon@google.com5ffd5ba2012-03-01 15:29:07 +0000129 ++N;
bsalomon@google.com96e96df2011-10-10 14:49:29 +0000130#endif
bsalomon@google.comc1dd8882012-03-02 20:36:18 +0000131 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));
bsalomon@google.com5ffd5ba2012-03-01 15:29:07 +0000139 } else {
bsalomon@google.com5ffd5ba2012-03-01 15:29:07 +0000140 GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
141 }
bsalomon@google.comc1dd8882012-03-02 20:36:18 +0000142#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000143 return true;
144}
145