bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2013 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 | #include "GrGLBufferImpl.h" |
| 9 | #include "GrGpuGL.h" |
| 10 | |
| 11 | #define GL_CALL(GPU, X) GR_GL_CALL(GPU->glInterface(), X) |
| 12 | |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 13 | #if GR_DEBUG |
| 14 | #define VALIDATE() this->validate() |
| 15 | #else |
| 16 | #define VALIDATE() do {} while(false) |
| 17 | #endif |
| 18 | |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 19 | GrGLBufferImpl::GrGLBufferImpl(GrGpuGL* gpu, const Desc& desc, GrGLenum bufferType) |
| 20 | : fDesc(desc) |
| 21 | , fBufferType(bufferType) |
| 22 | , fLockPtr(NULL) { |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 23 | if (0 == desc.fID) { |
| 24 | fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW); |
| 25 | } else { |
| 26 | fCPUData = NULL; |
| 27 | } |
| 28 | VALIDATE(); |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 29 | } |
| 30 | |
| 31 | void GrGLBufferImpl::release(GrGpuGL* gpu) { |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 32 | // make sure we've not been abandoned or already released |
| 33 | if (NULL != fCPUData) { |
| 34 | VALIDATE(); |
| 35 | sk_free(fCPUData); |
| 36 | fCPUData = NULL; |
| 37 | } else if (fDesc.fID && !fDesc.fIsWrapped) { |
| 38 | VALIDATE(); |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 39 | GL_CALL(gpu, DeleteBuffers(1, &fDesc.fID)); |
| 40 | if (GR_GL_ARRAY_BUFFER == fBufferType) { |
| 41 | gpu->notifyVertexBufferDelete(fDesc.fID); |
| 42 | } else { |
| 43 | GrAssert(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); |
| 44 | gpu->notifyIndexBufferDelete(fDesc.fID); |
| 45 | } |
| 46 | fDesc.fID = 0; |
| 47 | } |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 48 | fLockPtr = NULL; |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | void GrGLBufferImpl::abandon() { |
| 52 | fDesc.fID = 0; |
| 53 | fLockPtr = NULL; |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 54 | sk_free(fCPUData); |
| 55 | fCPUData = NULL; |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | void GrGLBufferImpl::bind(GrGpuGL* gpu) const { |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 59 | VALIDATE(); |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 60 | GL_CALL(gpu, BindBuffer(fBufferType, fDesc.fID)); |
| 61 | if (GR_GL_ARRAY_BUFFER == fBufferType) { |
| 62 | gpu->notifyVertexBufferBind(fDesc.fID); |
| 63 | } else { |
| 64 | GrAssert(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); |
| 65 | gpu->notifyIndexBufferBind(fDesc.fID); |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | void* GrGLBufferImpl::lock(GrGpuGL* gpu) { |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 70 | VALIDATE(); |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 71 | GrAssert(!this->isLocked()); |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 72 | if (0 == fDesc.fID) { |
| 73 | fLockPtr = fCPUData; |
| 74 | } else if (gpu->getCaps().bufferLockSupport()) { |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 75 | this->bind(gpu); |
| 76 | // Let driver know it can discard the old data |
| 77 | GL_CALL(gpu, BufferData(fBufferType, |
| 78 | fDesc.fSizeInBytes, |
| 79 | NULL, |
| 80 | fDesc.fDynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW)); |
| 81 | GR_GL_CALL_RET(gpu->glInterface(), |
| 82 | fLockPtr, |
| 83 | MapBuffer(fBufferType, GR_GL_WRITE_ONLY)); |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 84 | } |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 85 | return fLockPtr; |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | void GrGLBufferImpl::unlock(GrGpuGL* gpu) { |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 89 | VALIDATE(); |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 90 | GrAssert(this->isLocked()); |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 91 | if (0 != fDesc.fID) { |
| 92 | GrAssert(gpu->getCaps().bufferLockSupport()); |
| 93 | this->bind(gpu); |
| 94 | GL_CALL(gpu, UnmapBuffer(fBufferType)); |
| 95 | } |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 96 | fLockPtr = NULL; |
| 97 | } |
| 98 | |
| 99 | bool GrGLBufferImpl::isLocked() const { |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 100 | VALIDATE(); |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 101 | return NULL != fLockPtr; |
| 102 | } |
| 103 | |
| 104 | bool GrGLBufferImpl::updateData(GrGpuGL* gpu, const void* src, size_t srcSizeInBytes) { |
| 105 | GrAssert(!this->isLocked()); |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 106 | VALIDATE(); |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 107 | if (srcSizeInBytes > fDesc.fSizeInBytes) { |
| 108 | return false; |
| 109 | } |
| 110 | if (0 == fDesc.fID) { |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 111 | memcpy(fCPUData, src, srcSizeInBytes); |
| 112 | return true; |
bsalomon@google.com | e49ad45 | 2013-02-20 19:33:20 +0000 | [diff] [blame] | 113 | } |
| 114 | this->bind(gpu); |
| 115 | GrGLenum usage = fDesc.fDynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW; |
| 116 | |
| 117 | #if GR_GL_USE_BUFFER_DATA_NULL_HINT |
| 118 | if (fDesc.fSizeInBytes == srcSizeInBytes) { |
| 119 | GL_CALL(gpu, BufferData(fBufferType, srcSizeInBytes, src, usage)); |
| 120 | } else { |
| 121 | // Before we call glBufferSubData we give the driver a hint using |
| 122 | // glBufferData with NULL. This makes the old buffer contents |
| 123 | // inaccessible to future draws. The GPU may still be processing |
| 124 | // draws that reference the old contents. With this hint it can |
| 125 | // assign a different allocation for the new contents to avoid |
| 126 | // flushing the gpu past draws consuming the old contents. |
| 127 | GL_CALL(gpu, BufferData(fBufferType, fDesc.fSizeInBytes, NULL, usage)); |
| 128 | GL_CALL(gpu, BufferSubData(fBufferType, 0, srcSizeInBytes, src)); |
| 129 | } |
| 130 | #else |
| 131 | // Note that we're cheating on the size here. Currently no methods |
| 132 | // allow a partial update that preserves contents of non-updated |
| 133 | // portions of the buffer (lock() does a glBufferData(..size, NULL..)) |
| 134 | bool doSubData = false; |
| 135 | #if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND |
| 136 | static int N = 0; |
| 137 | // 128 was chosen experimentally. At 256 a slight hitchiness was noticed |
| 138 | // when dragging a Chromium window around with a canvas tab backgrounded. |
| 139 | doSubData = 0 == (N % 128); |
| 140 | ++N; |
| 141 | #endif |
| 142 | if (doSubData) { |
| 143 | // The workaround is to do a glBufferData followed by glBufferSubData. |
| 144 | // Chromium's command buffer may turn a glBufferSubData where the size |
| 145 | // exactly matches the buffer size into a glBufferData. So we tack 1 |
| 146 | // extra byte onto the glBufferData. |
| 147 | GL_CALL(gpu, BufferData(fBufferType, srcSizeInBytes + 1, NULL, usage)); |
| 148 | GL_CALL(gpu, BufferSubData(fBufferType, 0, srcSizeInBytes, src)); |
| 149 | } else { |
| 150 | GL_CALL(gpu, BufferData(fBufferType, srcSizeInBytes, src, usage)); |
| 151 | } |
| 152 | #endif |
| 153 | return true; |
| 154 | } |
bsalomon@google.com | ee3bc3b | 2013-02-21 14:33:46 +0000 | [diff] [blame] | 155 | |
| 156 | void GrGLBufferImpl::validate() const { |
| 157 | GrAssert(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); |
| 158 | GrAssert((0 == fDesc.fID) == (NULL != fCPUData)); |
| 159 | GrAssert(0 != fDesc.fID || !fDesc.fIsWrapped); |
| 160 | GrAssert(NULL == fCPUData || NULL == fLockPtr || fCPUData == fLockPtr); |
| 161 | } |