gfx/skia/trunk/src/gpu/gl/GrGLBufferImpl.cpp

changeset 0
6474c204b198
     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 +}

mercurial