| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrGLBufferImpl.h" | 8 #include "GrGLBufferImpl.h" |
| 9 #include "GrGLGpu.h" | 9 #include "GrGLGpu.h" |
| 10 | 10 |
| 11 #define GL_CALL(GPU, X) GR_GL_CALL(GPU->glInterface(), X) | 11 #define GL_CALL(GPU, X) GR_GL_CALL(GPU->glInterface(), X) |
| 12 | 12 |
| 13 #ifdef SK_DEBUG | 13 #ifdef SK_DEBUG |
| 14 #define VALIDATE() this->validate() | 14 #define VALIDATE() this->validate() |
| 15 #else | 15 #else |
| 16 #define VALIDATE() do {} while(false) | 16 #define VALIDATE() do {} while(false) |
| 17 #endif | 17 #endif |
| 18 | 18 |
| 19 // GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a cli
ent's vertex buffer | 19 // GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a cli
ent's vertex buffer |
| 20 // objects are implemented as client-side-arrays on tile-deferred architectures. | 20 // objects are implemented as client-side-arrays on tile-deferred architectures. |
| 21 #define DYNAMIC_USAGE_PARAM GR_GL_STREAM_DRAW | 21 #define DYNAMIC_USAGE_PARAM GR_GL_STREAM_DRAW |
| 22 | 22 |
| 23 GrGLBufferImpl::GrGLBufferImpl(GrGLGpu* gpu, const Desc& desc, GrGLenum bufferTy
pe) | 23 GrGLBufferImpl::GrGLBufferImpl(GrGLGpu* gpu, const Desc& desc, GrGLenum bufferTy
pe) |
| 24 : fDesc(desc) | 24 : fDesc(desc) |
| 25 , fBufferType(bufferType) | 25 , fBufferType(bufferType) |
| 26 , fMapPtr(NULL) { | 26 , fMapPtr(nullptr) { |
| 27 if (0 == desc.fID) { | 27 if (0 == desc.fID) { |
| 28 if (gpu->caps()->mustClearUploadedBufferData()) { | 28 if (gpu->caps()->mustClearUploadedBufferData()) { |
| 29 fCPUData = sk_calloc_throw(desc.fSizeInBytes); | 29 fCPUData = sk_calloc_throw(desc.fSizeInBytes); |
| 30 } else { | 30 } else { |
| 31 fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW); | 31 fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW); |
| 32 } | 32 } |
| 33 fGLSizeInBytes = 0; | 33 fGLSizeInBytes = 0; |
| 34 } else { | 34 } else { |
| 35 fCPUData = NULL; | 35 fCPUData = nullptr; |
| 36 // We assume that the GL buffer was created at the desc's size initially
. | 36 // We assume that the GL buffer was created at the desc's size initially
. |
| 37 fGLSizeInBytes = fDesc.fSizeInBytes; | 37 fGLSizeInBytes = fDesc.fSizeInBytes; |
| 38 } | 38 } |
| 39 VALIDATE(); | 39 VALIDATE(); |
| 40 } | 40 } |
| 41 | 41 |
| 42 void GrGLBufferImpl::release(GrGLGpu* gpu) { | 42 void GrGLBufferImpl::release(GrGLGpu* gpu) { |
| 43 VALIDATE(); | 43 VALIDATE(); |
| 44 // make sure we've not been abandoned or already released | 44 // make sure we've not been abandoned or already released |
| 45 if (fCPUData) { | 45 if (fCPUData) { |
| 46 sk_free(fCPUData); | 46 sk_free(fCPUData); |
| 47 fCPUData = NULL; | 47 fCPUData = nullptr; |
| 48 } else if (fDesc.fID) { | 48 } else if (fDesc.fID) { |
| 49 GL_CALL(gpu, DeleteBuffers(1, &fDesc.fID)); | 49 GL_CALL(gpu, DeleteBuffers(1, &fDesc.fID)); |
| 50 if (GR_GL_ARRAY_BUFFER == fBufferType) { | 50 if (GR_GL_ARRAY_BUFFER == fBufferType) { |
| 51 gpu->notifyVertexBufferDelete(fDesc.fID); | 51 gpu->notifyVertexBufferDelete(fDesc.fID); |
| 52 } else { | 52 } else { |
| 53 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); | 53 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); |
| 54 gpu->notifyIndexBufferDelete(fDesc.fID); | 54 gpu->notifyIndexBufferDelete(fDesc.fID); |
| 55 } | 55 } |
| 56 fDesc.fID = 0; | 56 fDesc.fID = 0; |
| 57 fGLSizeInBytes = 0; | 57 fGLSizeInBytes = 0; |
| 58 } | 58 } |
| 59 fMapPtr = NULL; | 59 fMapPtr = nullptr; |
| 60 VALIDATE(); | 60 VALIDATE(); |
| 61 } | 61 } |
| 62 | 62 |
| 63 void GrGLBufferImpl::abandon() { | 63 void GrGLBufferImpl::abandon() { |
| 64 fDesc.fID = 0; | 64 fDesc.fID = 0; |
| 65 fGLSizeInBytes = 0; | 65 fGLSizeInBytes = 0; |
| 66 fMapPtr = NULL; | 66 fMapPtr = nullptr; |
| 67 sk_free(fCPUData); | 67 sk_free(fCPUData); |
| 68 fCPUData = NULL; | 68 fCPUData = nullptr; |
| 69 VALIDATE(); | 69 VALIDATE(); |
| 70 } | 70 } |
| 71 | 71 |
| 72 void GrGLBufferImpl::bind(GrGLGpu* gpu) const { | 72 void GrGLBufferImpl::bind(GrGLGpu* gpu) const { |
| 73 VALIDATE(); | 73 VALIDATE(); |
| 74 if (GR_GL_ARRAY_BUFFER == fBufferType) { | 74 if (GR_GL_ARRAY_BUFFER == fBufferType) { |
| 75 gpu->bindVertexBuffer(fDesc.fID); | 75 gpu->bindVertexBuffer(fDesc.fID); |
| 76 } else { | 76 } else { |
| 77 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); | 77 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); |
| 78 gpu->bindIndexBufferAndDefaultVertexArray(fDesc.fID); | 78 gpu->bindIndexBufferAndDefaultVertexArray(fDesc.fID); |
| 79 } | 79 } |
| 80 VALIDATE(); | 80 VALIDATE(); |
| 81 } | 81 } |
| 82 | 82 |
| 83 void* GrGLBufferImpl::map(GrGLGpu* gpu) { | 83 void* GrGLBufferImpl::map(GrGLGpu* gpu) { |
| 84 VALIDATE(); | 84 VALIDATE(); |
| 85 SkASSERT(!this->isMapped()); | 85 SkASSERT(!this->isMapped()); |
| 86 if (0 == fDesc.fID) { | 86 if (0 == fDesc.fID) { |
| 87 fMapPtr = fCPUData; | 87 fMapPtr = fCPUData; |
| 88 } else { | 88 } else { |
| 89 switch (gpu->glCaps().mapBufferType()) { | 89 switch (gpu->glCaps().mapBufferType()) { |
| 90 case GrGLCaps::kNone_MapBufferType: | 90 case GrGLCaps::kNone_MapBufferType: |
| 91 VALIDATE(); | 91 VALIDATE(); |
| 92 return NULL; | 92 return nullptr; |
| 93 case GrGLCaps::kMapBuffer_MapBufferType: | 93 case GrGLCaps::kMapBuffer_MapBufferType: |
| 94 this->bind(gpu); | 94 this->bind(gpu); |
| 95 // Let driver know it can discard the old data | 95 // Let driver know it can discard the old data |
| 96 if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fDesc.fSizeInBytes != fGL
SizeInBytes) { | 96 if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fDesc.fSizeInBytes != fGL
SizeInBytes) { |
| 97 fGLSizeInBytes = fDesc.fSizeInBytes; | 97 fGLSizeInBytes = fDesc.fSizeInBytes; |
| 98 GL_CALL(gpu, | 98 GL_CALL(gpu, |
| 99 BufferData(fBufferType, fGLSizeInBytes, NULL, | 99 BufferData(fBufferType, fGLSizeInBytes, nullptr, |
| 100 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); | 100 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); |
| 101 } | 101 } |
| 102 GR_GL_CALL_RET(gpu->glInterface(), fMapPtr, | 102 GR_GL_CALL_RET(gpu->glInterface(), fMapPtr, |
| 103 MapBuffer(fBufferType, GR_GL_WRITE_ONLY)); | 103 MapBuffer(fBufferType, GR_GL_WRITE_ONLY)); |
| 104 break; | 104 break; |
| 105 case GrGLCaps::kMapBufferRange_MapBufferType: { | 105 case GrGLCaps::kMapBufferRange_MapBufferType: { |
| 106 this->bind(gpu); | 106 this->bind(gpu); |
| 107 // Make sure the GL buffer size agrees with fDesc before mapping
. | 107 // Make sure the GL buffer size agrees with fDesc before mapping
. |
| 108 if (fDesc.fSizeInBytes != fGLSizeInBytes) { | 108 if (fDesc.fSizeInBytes != fGLSizeInBytes) { |
| 109 fGLSizeInBytes = fDesc.fSizeInBytes; | 109 fGLSizeInBytes = fDesc.fSizeInBytes; |
| 110 GL_CALL(gpu, | 110 GL_CALL(gpu, |
| 111 BufferData(fBufferType, fGLSizeInBytes, NULL, | 111 BufferData(fBufferType, fGLSizeInBytes, nullptr, |
| 112 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); | 112 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); |
| 113 } | 113 } |
| 114 static const GrGLbitfield kAccess = GR_GL_MAP_INVALIDATE_BUFFER_
BIT | | 114 static const GrGLbitfield kAccess = GR_GL_MAP_INVALIDATE_BUFFER_
BIT | |
| 115 GR_GL_MAP_WRITE_BIT; | 115 GR_GL_MAP_WRITE_BIT; |
| 116 GR_GL_CALL_RET(gpu->glInterface(), | 116 GR_GL_CALL_RET(gpu->glInterface(), |
| 117 fMapPtr, | 117 fMapPtr, |
| 118 MapBufferRange(fBufferType, 0, fGLSizeInBytes, kA
ccess)); | 118 MapBufferRange(fBufferType, 0, fGLSizeInBytes, kA
ccess)); |
| 119 break; | 119 break; |
| 120 } | 120 } |
| 121 case GrGLCaps::kChromium_MapBufferType: | 121 case GrGLCaps::kChromium_MapBufferType: |
| 122 this->bind(gpu); | 122 this->bind(gpu); |
| 123 // Make sure the GL buffer size agrees with fDesc before mapping
. | 123 // Make sure the GL buffer size agrees with fDesc before mapping
. |
| 124 if (fDesc.fSizeInBytes != fGLSizeInBytes) { | 124 if (fDesc.fSizeInBytes != fGLSizeInBytes) { |
| 125 fGLSizeInBytes = fDesc.fSizeInBytes; | 125 fGLSizeInBytes = fDesc.fSizeInBytes; |
| 126 GL_CALL(gpu, | 126 GL_CALL(gpu, |
| 127 BufferData(fBufferType, fGLSizeInBytes, NULL, | 127 BufferData(fBufferType, fGLSizeInBytes, nullptr, |
| 128 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); | 128 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); |
| 129 } | 129 } |
| 130 GR_GL_CALL_RET(gpu->glInterface(), | 130 GR_GL_CALL_RET(gpu->glInterface(), |
| 131 fMapPtr, | 131 fMapPtr, |
| 132 MapBufferSubData(fBufferType, 0, fGLSizeInBytes,
GR_GL_WRITE_ONLY)); | 132 MapBufferSubData(fBufferType, 0, fGLSizeInBytes,
GR_GL_WRITE_ONLY)); |
| 133 break; | 133 break; |
| 134 } | 134 } |
| 135 } | 135 } |
| 136 VALIDATE(); | 136 VALIDATE(); |
| 137 return fMapPtr; | 137 return fMapPtr; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 149 case GrGLCaps::kMapBufferRange_MapBufferType: | 149 case GrGLCaps::kMapBufferRange_MapBufferType: |
| 150 this->bind(gpu); | 150 this->bind(gpu); |
| 151 GL_CALL(gpu, UnmapBuffer(fBufferType)); | 151 GL_CALL(gpu, UnmapBuffer(fBufferType)); |
| 152 break; | 152 break; |
| 153 case GrGLCaps::kChromium_MapBufferType: | 153 case GrGLCaps::kChromium_MapBufferType: |
| 154 this->bind(gpu); | 154 this->bind(gpu); |
| 155 GR_GL_CALL(gpu->glInterface(), UnmapBufferSubData(fMapPtr)); | 155 GR_GL_CALL(gpu->glInterface(), UnmapBufferSubData(fMapPtr)); |
| 156 break; | 156 break; |
| 157 } | 157 } |
| 158 } | 158 } |
| 159 fMapPtr = NULL; | 159 fMapPtr = nullptr; |
| 160 } | 160 } |
| 161 | 161 |
| 162 bool GrGLBufferImpl::isMapped() const { | 162 bool GrGLBufferImpl::isMapped() const { |
| 163 VALIDATE(); | 163 VALIDATE(); |
| 164 return SkToBool(fMapPtr); | 164 return SkToBool(fMapPtr); |
| 165 } | 165 } |
| 166 | 166 |
| 167 bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInB
ytes) { | 167 bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInB
ytes) { |
| 168 SkASSERT(!this->isMapped()); | 168 SkASSERT(!this->isMapped()); |
| 169 VALIDATE(); | 169 VALIDATE(); |
| 170 if (srcSizeInBytes > fDesc.fSizeInBytes) { | 170 if (srcSizeInBytes > fDesc.fSizeInBytes) { |
| 171 return false; | 171 return false; |
| 172 } | 172 } |
| 173 if (0 == fDesc.fID) { | 173 if (0 == fDesc.fID) { |
| 174 memcpy(fCPUData, src, srcSizeInBytes); | 174 memcpy(fCPUData, src, srcSizeInBytes); |
| 175 return true; | 175 return true; |
| 176 } | 176 } |
| 177 this->bind(gpu); | 177 this->bind(gpu); |
| 178 GrGLenum usage = fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW; | 178 GrGLenum usage = fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW; |
| 179 | 179 |
| 180 #if GR_GL_USE_BUFFER_DATA_NULL_HINT | 180 #if GR_GL_USE_BUFFER_DATA_NULL_HINT |
| 181 if (fDesc.fSizeInBytes == srcSizeInBytes) { | 181 if (fDesc.fSizeInBytes == srcSizeInBytes) { |
| 182 GL_CALL(gpu, BufferData(fBufferType, (GrGLsizeiptr) srcSizeInBytes, src,
usage)); | 182 GL_CALL(gpu, BufferData(fBufferType, (GrGLsizeiptr) srcSizeInBytes, src,
usage)); |
| 183 } else { | 183 } else { |
| 184 // Before we call glBufferSubData we give the driver a hint using | 184 // Before we call glBufferSubData we give the driver a hint using |
| 185 // glBufferData with NULL. This makes the old buffer contents | 185 // glBufferData with nullptr. This makes the old buffer contents |
| 186 // inaccessible to future draws. The GPU may still be processing | 186 // inaccessible to future draws. The GPU may still be processing |
| 187 // draws that reference the old contents. With this hint it can | 187 // draws that reference the old contents. With this hint it can |
| 188 // assign a different allocation for the new contents to avoid | 188 // assign a different allocation for the new contents to avoid |
| 189 // flushing the gpu past draws consuming the old contents. | 189 // flushing the gpu past draws consuming the old contents. |
| 190 fGLSizeInBytes = fDesc.fSizeInBytes; | 190 fGLSizeInBytes = fDesc.fSizeInBytes; |
| 191 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, NULL, usage)); | 191 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, nullptr, usage)); |
| 192 GL_CALL(gpu, BufferSubData(fBufferType, 0, (GrGLsizeiptr) srcSizeInBytes
, src)); | 192 GL_CALL(gpu, BufferSubData(fBufferType, 0, (GrGLsizeiptr) srcSizeInBytes
, src)); |
| 193 } | 193 } |
| 194 #else | 194 #else |
| 195 // Note that we're cheating on the size here. Currently no methods | 195 // Note that we're cheating on the size here. Currently no methods |
| 196 // allow a partial update that preserves contents of non-updated | 196 // allow a partial update that preserves contents of non-updated |
| 197 // portions of the buffer (map() does a glBufferData(..size, NULL..)) | 197 // portions of the buffer (map() does a glBufferData(..size, nullptr..)) |
| 198 bool doSubData = false; | 198 bool doSubData = false; |
| 199 #if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND | 199 #if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND |
| 200 static int N = 0; | 200 static int N = 0; |
| 201 // 128 was chosen experimentally. At 256 a slight hitchiness was noticed | 201 // 128 was chosen experimentally. At 256 a slight hitchiness was noticed |
| 202 // when dragging a Chromium window around with a canvas tab backgrounded. | 202 // when dragging a Chromium window around with a canvas tab backgrounded. |
| 203 doSubData = 0 == (N % 128); | 203 doSubData = 0 == (N % 128); |
| 204 ++N; | 204 ++N; |
| 205 #endif | 205 #endif |
| 206 if (doSubData) { | 206 if (doSubData) { |
| 207 // The workaround is to do a glBufferData followed by glBufferSubData. | 207 // The workaround is to do a glBufferData followed by glBufferSubData. |
| 208 // Chromium's command buffer may turn a glBufferSubData where the size | 208 // Chromium's command buffer may turn a glBufferSubData where the size |
| 209 // exactly matches the buffer size into a glBufferData. So we tack 1 | 209 // exactly matches the buffer size into a glBufferData. So we tack 1 |
| 210 // extra byte onto the glBufferData. | 210 // extra byte onto the glBufferData. |
| 211 fGLSizeInBytes = srcSizeInBytes + 1; | 211 fGLSizeInBytes = srcSizeInBytes + 1; |
| 212 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, NULL, usage)); | 212 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, nullptr, usage)); |
| 213 GL_CALL(gpu, BufferSubData(fBufferType, 0, srcSizeInBytes, src)); | 213 GL_CALL(gpu, BufferSubData(fBufferType, 0, srcSizeInBytes, src)); |
| 214 } else { | 214 } else { |
| 215 fGLSizeInBytes = srcSizeInBytes; | 215 fGLSizeInBytes = srcSizeInBytes; |
| 216 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, src, usage)); | 216 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, src, usage)); |
| 217 } | 217 } |
| 218 #endif | 218 #endif |
| 219 return true; | 219 return true; |
| 220 } | 220 } |
| 221 | 221 |
| 222 void GrGLBufferImpl::validate() const { | 222 void GrGLBufferImpl::validate() const { |
| 223 SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER ==
fBufferType); | 223 SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER ==
fBufferType); |
| 224 // The following assert isn't valid when the buffer has been abandoned: | 224 // The following assert isn't valid when the buffer has been abandoned: |
| 225 // SkASSERT((0 == fDesc.fID) == (fCPUData)); | 225 // SkASSERT((0 == fDesc.fID) == (fCPUData)); |
| 226 SkASSERT(NULL == fCPUData || 0 == fGLSizeInBytes); | 226 SkASSERT(nullptr == fCPUData || 0 == fGLSizeInBytes); |
| 227 SkASSERT(NULL == fMapPtr || fCPUData || fGLSizeInBytes == fDesc.fSizeInBytes
); | 227 SkASSERT(nullptr == fMapPtr || fCPUData || fGLSizeInBytes == fDesc.fSizeInBy
tes); |
| 228 SkASSERT(NULL == fCPUData || NULL == fMapPtr || fCPUData == fMapPtr); | 228 SkASSERT(nullptr == fCPUData || nullptr == fMapPtr || fCPUData == fMapPtr); |
| 229 } | 229 } |
| OLD | NEW |