1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/gl/GrGLBufferImpl.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,165 @@ 1.4 +/* 1.5 + * Copyright 2013 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "GrGLBufferImpl.h" 1.12 +#include "GrGpuGL.h" 1.13 + 1.14 +#define GL_CALL(GPU, X) GR_GL_CALL(GPU->glInterface(), X) 1.15 + 1.16 +#ifdef SK_DEBUG 1.17 +#define VALIDATE() this->validate() 1.18 +#else 1.19 +#define VALIDATE() do {} while(false) 1.20 +#endif 1.21 + 1.22 +// GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a client's vertex buffer 1.23 +// objects are implemented as client-side-arrays on tile-deferred architectures. 1.24 +#define DYNAMIC_USAGE_PARAM GR_GL_STREAM_DRAW 1.25 + 1.26 +GrGLBufferImpl::GrGLBufferImpl(GrGpuGL* gpu, const Desc& desc, GrGLenum bufferType) 1.27 + : fDesc(desc) 1.28 + , fBufferType(bufferType) 1.29 + , fLockPtr(NULL) { 1.30 + if (0 == desc.fID) { 1.31 + fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW); 1.32 + } else { 1.33 + fCPUData = NULL; 1.34 + } 1.35 + VALIDATE(); 1.36 +} 1.37 + 1.38 +void GrGLBufferImpl::release(GrGpuGL* gpu) { 1.39 + // make sure we've not been abandoned or already released 1.40 + if (NULL != fCPUData) { 1.41 + VALIDATE(); 1.42 + sk_free(fCPUData); 1.43 + fCPUData = NULL; 1.44 + } else if (fDesc.fID && !fDesc.fIsWrapped) { 1.45 + VALIDATE(); 1.46 + GL_CALL(gpu, DeleteBuffers(1, &fDesc.fID)); 1.47 + if (GR_GL_ARRAY_BUFFER == fBufferType) { 1.48 + gpu->notifyVertexBufferDelete(fDesc.fID); 1.49 + } else { 1.50 + SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); 1.51 + gpu->notifyIndexBufferDelete(fDesc.fID); 1.52 + } 1.53 + fDesc.fID = 0; 1.54 + } 1.55 + fLockPtr = NULL; 1.56 +} 1.57 + 1.58 +void GrGLBufferImpl::abandon() { 1.59 + fDesc.fID = 0; 1.60 + fLockPtr = NULL; 1.61 + sk_free(fCPUData); 1.62 + fCPUData = NULL; 1.63 +} 1.64 + 1.65 +void GrGLBufferImpl::bind(GrGpuGL* gpu) const { 1.66 + VALIDATE(); 1.67 + if (GR_GL_ARRAY_BUFFER == fBufferType) { 1.68 + gpu->bindVertexBuffer(fDesc.fID); 1.69 + } else { 1.70 + SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); 1.71 + gpu->bindIndexBufferAndDefaultVertexArray(fDesc.fID); 1.72 + } 1.73 +} 1.74 + 1.75 +void* GrGLBufferImpl::lock(GrGpuGL* gpu) { 1.76 + VALIDATE(); 1.77 + SkASSERT(!this->isLocked()); 1.78 + if (0 == fDesc.fID) { 1.79 + fLockPtr = fCPUData; 1.80 + } else if (gpu->caps()->bufferLockSupport()) { 1.81 + this->bind(gpu); 1.82 + // Let driver know it can discard the old data 1.83 + GL_CALL(gpu, BufferData(fBufferType, 1.84 + (GrGLsizeiptr) fDesc.fSizeInBytes, 1.85 + NULL, 1.86 + fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW)); 1.87 + GR_GL_CALL_RET(gpu->glInterface(), 1.88 + fLockPtr, 1.89 + MapBuffer(fBufferType, GR_GL_WRITE_ONLY)); 1.90 + } 1.91 + return fLockPtr; 1.92 +} 1.93 + 1.94 +void GrGLBufferImpl::unlock(GrGpuGL* gpu) { 1.95 + VALIDATE(); 1.96 + SkASSERT(this->isLocked()); 1.97 + if (0 != fDesc.fID) { 1.98 + SkASSERT(gpu->caps()->bufferLockSupport()); 1.99 + this->bind(gpu); 1.100 + GL_CALL(gpu, UnmapBuffer(fBufferType)); 1.101 + } 1.102 + fLockPtr = NULL; 1.103 +} 1.104 + 1.105 +bool GrGLBufferImpl::isLocked() const { 1.106 + VALIDATE(); 1.107 + return NULL != fLockPtr; 1.108 +} 1.109 + 1.110 +bool GrGLBufferImpl::updateData(GrGpuGL* gpu, const void* src, size_t srcSizeInBytes) { 1.111 + SkASSERT(!this->isLocked()); 1.112 + VALIDATE(); 1.113 + if (srcSizeInBytes > fDesc.fSizeInBytes) { 1.114 + return false; 1.115 + } 1.116 + if (0 == fDesc.fID) { 1.117 + memcpy(fCPUData, src, srcSizeInBytes); 1.118 + return true; 1.119 + } 1.120 + this->bind(gpu); 1.121 + GrGLenum usage = fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW; 1.122 + 1.123 +#if GR_GL_USE_BUFFER_DATA_NULL_HINT 1.124 + if (fDesc.fSizeInBytes == srcSizeInBytes) { 1.125 + GL_CALL(gpu, BufferData(fBufferType, (GrGLsizeiptr) srcSizeInBytes, src, usage)); 1.126 + } else { 1.127 + // Before we call glBufferSubData we give the driver a hint using 1.128 + // glBufferData with NULL. This makes the old buffer contents 1.129 + // inaccessible to future draws. The GPU may still be processing 1.130 + // draws that reference the old contents. With this hint it can 1.131 + // assign a different allocation for the new contents to avoid 1.132 + // flushing the gpu past draws consuming the old contents. 1.133 + GL_CALL(gpu, BufferData(fBufferType, (GrGLsizeiptr) fDesc.fSizeInBytes, NULL, usage)); 1.134 + GL_CALL(gpu, BufferSubData(fBufferType, 0, (GrGLsizeiptr) srcSizeInBytes, src)); 1.135 + } 1.136 +#else 1.137 + // Note that we're cheating on the size here. Currently no methods 1.138 + // allow a partial update that preserves contents of non-updated 1.139 + // portions of the buffer (lock() does a glBufferData(..size, NULL..)) 1.140 + bool doSubData = false; 1.141 +#if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND 1.142 + static int N = 0; 1.143 + // 128 was chosen experimentally. At 256 a slight hitchiness was noticed 1.144 + // when dragging a Chromium window around with a canvas tab backgrounded. 1.145 + doSubData = 0 == (N % 128); 1.146 + ++N; 1.147 +#endif 1.148 + if (doSubData) { 1.149 + // The workaround is to do a glBufferData followed by glBufferSubData. 1.150 + // Chromium's command buffer may turn a glBufferSubData where the size 1.151 + // exactly matches the buffer size into a glBufferData. So we tack 1 1.152 + // extra byte onto the glBufferData. 1.153 + GL_CALL(gpu, BufferData(fBufferType, srcSizeInBytes + 1, NULL, usage)); 1.154 + GL_CALL(gpu, BufferSubData(fBufferType, 0, srcSizeInBytes, src)); 1.155 + } else { 1.156 + GL_CALL(gpu, BufferData(fBufferType, srcSizeInBytes, src, usage)); 1.157 + } 1.158 +#endif 1.159 + return true; 1.160 +} 1.161 + 1.162 +void GrGLBufferImpl::validate() const { 1.163 + SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); 1.164 + // The following assert isn't valid when the buffer has been abandoned: 1.165 + // SkASSERT((0 == fDesc.fID) == (NULL != fCPUData)); 1.166 + SkASSERT(0 != fDesc.fID || !fDesc.fIsWrapped); 1.167 + SkASSERT(NULL == fCPUData || NULL == fLockPtr || fCPUData == fLockPtr); 1.168 +}