bool GrGLBufferImpl::updateData(GrGpuGL* gpu, const void* src, size_t srcSizeInBytes) { SkASSERT(!this->isMapped()); VALIDATE(); if (srcSizeInBytes > fDesc.fSizeInBytes) { return false; } if (0 == fDesc.fID) { memcpy(fCPUData, src, srcSizeInBytes); return true; } this->bind(gpu); GrGLenum usage = fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW; #if GR_GL_USE_BUFFER_DATA_NULL_HINT if (fDesc.fSizeInBytes == srcSizeInBytes) { GL_CALL(gpu, BufferData(fBufferType, (GrGLsizeiptr) srcSizeInBytes, src, usage)); } else { // Before we call glBufferSubData we give the driver a hint using // glBufferData with NULL. This makes the old buffer contents // inaccessible to future draws. The GPU may still be processing // draws that reference the old contents. With this hint it can // assign a different allocation for the new contents to avoid // flushing the gpu past draws consuming the old contents. fGLSizeInBytes = fDesc.fSizeInBytes; GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, NULL, usage)); GL_CALL(gpu, BufferSubData(fBufferType, 0, (GrGLsizeiptr) srcSizeInBytes, src)); } #else // Note that we're cheating on the size here. Currently no methods // allow a partial update that preserves contents of non-updated // portions of the buffer (map() does a glBufferData(..size, NULL..)) bool doSubData = false; #if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND static int N = 0; // 128 was chosen experimentally. At 256 a slight hitchiness was noticed // when dragging a Chromium window around with a canvas tab backgrounded. doSubData = 0 == (N % 128); ++N; #endif if (doSubData) { // The workaround is to do a glBufferData followed by glBufferSubData. // Chromium's command buffer may turn a glBufferSubData where the size // exactly matches the buffer size into a glBufferData. So we tack 1 // extra byte onto the glBufferData. fGLSizeInBytes = srcSizeInBytes + 1; GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, NULL, usage)); GL_CALL(gpu, BufferSubData(fBufferType, 0, srcSizeInBytes, src)); } else { fGLSizeInBytes = srcSizeInBytes; GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, src, usage)); } #endif return true; }
bool GrGLVertexBuffer::updateData(const void* src, size_t srcSizeInBytes) { GrAssert(fBufferID); GrAssert(!isLocked()); if (srcSizeInBytes > this->sizeInBytes()) { return false; } this->bind(); GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW; #if GR_GL_USE_BUFFER_DATA_NULL_HINT if (this->sizeInBytes() == srcSizeInBytes) { GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage)); } else { // Before we call glBufferSubData we give the driver a hint using // glBufferData with NULL. This makes the old buffer contents // inaccessible to future draws. The GPU may still be processing // draws that reference the old contents. With this hint it can // assign a different allocation for the new contents to avoid // flushing the gpu past draws consuming the old contents. GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, this->sizeInBytes(), NULL, usage)); GL_CALL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src)); } #else // Note that we're cheating on the size here. Currently no methods // allow a partial update that preserves contents of non-updated // portions of the buffer (lock() does a glBufferData(..size, NULL..)) bool doSubData = false; #if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND static int N = 0; // 128 was chosen experimentally. At 256 a slight hitchiness was noticed // when dragging a Chromium window around with a canvas tab backgrounded. doSubData = 0 == (N % 128); ++N; #endif if (doSubData) { // The workaround is to do a glBufferData followed by glBufferSubData. // Chromium's command buffer may turn a glBufferSubData where the size // exactly matches the buffer size into a glBufferData. So we tack 1 // extra byte onto the glBufferData. GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes + 1, NULL, usage)); GL_CALL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src)); } else { GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage)); } #endif return true; }
bool GrGLVertexBuffer::updateData(const void* src, size_t srcSizeInBytes) { GrAssert(fBufferID); GrAssert(!isLocked()); if (srcSizeInBytes > this->sizeInBytes()) { return false; } this->bind(); GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW; #if !GR_GL_USE_BUFFER_DATA_NULL_HINT // Note that we're cheating on the size here. Currently no methods // allow a partial update that preserves contents of non-updated // portions of the buffer (and lock() does a glBufferData(..size, NULL..)) GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage)); #else if (this->sizeInBytes() == srcSizeInBytes) { GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage)); } else { // Before we call glBufferSubData we give the driver a hint using // glBufferData with NULL. This makes the old buffer contents // inaccessible to future draws. The GPU may still be processing draws // that reference the old contents. With this hint it can assign a // different allocation for the new contents to avoid flushing the gpu // past draws consuming the old contents. GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, this->sizeInBytes(), NULL, usage)); GL_CALL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src)); } #endif return true; }
bool GrGLVertexBuffer::updateSubData(const void* src, size_t srcSizeInBytes, size_t offset) { GrAssert(fBufferID); GrAssert(!isLocked()); if (srcSizeInBytes + offset > size()) { return false; } this->bind(); GR_GL(BufferSubData(GR_GL_ARRAY_BUFFER, offset, srcSizeInBytes, src)); return true; }
bool GrGLVertexBuffer::updateData(const void* src, size_t srcSizeInBytes) { GrAssert(fBufferID); GrAssert(!isLocked()); if (srcSizeInBytes > size()) { return false; } this->bind(); GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW; if (size() == srcSizeInBytes) { GR_GL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage)); } else { GR_GL(BufferData(GR_GL_ARRAY_BUFFER, size(), NULL, usage)); GR_GL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src)); } return true; }
bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) { if (this->wasDestroyed()) { return false; } SkASSERT(!this->isMapped()); VALIDATE(); if (srcSizeInBytes > fSizeInBytes) { return false; } if (0 == fBufferID) { memcpy(fCPUData, src, srcSizeInBytes); return true; } SkASSERT(srcSizeInBytes <= fSizeInBytes); // bindbuffer handles dirty context GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this); #if GR_GL_USE_BUFFER_DATA_NULL_HINT if (fSizeInBytes == srcSizeInBytes) { GL_CALL(BufferData(target, (GrGLsizeiptr) srcSizeInBytes, src, fUsage)); } else { // Before we call glBufferSubData we give the driver a hint using // glBufferData with nullptr. This makes the old buffer contents // inaccessible to future draws. The GPU may still be processing // draws that reference the old contents. With this hint it can // assign a different allocation for the new contents to avoid // flushing the gpu past draws consuming the old contents. // TODO I think we actually want to try calling bufferData here GL_CALL(BufferData(target, fSizeInBytes, nullptr, fUsage)); GL_CALL(BufferSubData(target, 0, (GrGLsizeiptr) srcSizeInBytes, src)); } fGLSizeInBytes = fSizeInBytes; #else // Note that we're cheating on the size here. Currently no methods // allow a partial update that preserves contents of non-updated // portions of the buffer (map() does a glBufferData(..size, nullptr..)) GL_CALL(BufferData(target, srcSizeInBytes, src, fUsage)); fGLSizeInBytes = srcSizeInBytes; #endif VALIDATE(); return true; }