tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Buffer.cpp (14714B)


      1 //
      2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 // Buffer.cpp: Implements the gl::Buffer class, representing storage of vertex and/or
      8 // index data. Implements GL buffer objects and related functionality.
      9 // [OpenGL ES 2.0.24] section 2.9 page 21.
     10 
     11 #include "libANGLE/Buffer.h"
     12 
     13 #include "libANGLE/Context.h"
     14 #include "libANGLE/renderer/BufferImpl.h"
     15 #include "libANGLE/renderer/GLImplFactory.h"
     16 
     17 namespace gl
     18 {
     19 namespace
     20 {
     21 constexpr angle::SubjectIndex kImplementationSubjectIndex = 0;
     22 constexpr size_t kInvalidContentsObserverIndex            = std::numeric_limits<size_t>::max();
     23 }  // anonymous namespace
     24 
     25 BufferState::BufferState()
     26    : mLabel(),
     27      mUsage(BufferUsage::StaticDraw),
     28      mSize(0),
     29      mAccessFlags(0),
     30      mAccess(GL_WRITE_ONLY_OES),
     31      mMapped(GL_FALSE),
     32      mMapPointer(nullptr),
     33      mMapOffset(0),
     34      mMapLength(0),
     35      mBindingCount(0),
     36      mTransformFeedbackIndexedBindingCount(0),
     37      mTransformFeedbackGenericBindingCount(0),
     38      mImmutable(GL_FALSE),
     39      mStorageExtUsageFlags(0),
     40      mExternal(GL_FALSE)
     41 {}
     42 
     43 BufferState::~BufferState() {}
     44 
     45 Buffer::Buffer(rx::GLImplFactory *factory, BufferID id)
     46    : RefCountObject(factory->generateSerial(), id),
     47      mImpl(factory->createBuffer(mState)),
     48      mImplObserver(this, kImplementationSubjectIndex)
     49 {
     50    mImplObserver.bind(mImpl);
     51 }
     52 
     53 Buffer::~Buffer()
     54 {
     55    SafeDelete(mImpl);
     56 }
     57 
     58 void Buffer::onDestroy(const Context *context)
     59 {
     60    // In tests, mImpl might be null.
     61    if (mImpl)
     62        mImpl->destroy(context);
     63 }
     64 
     65 angle::Result Buffer::setLabel(const Context *context, const std::string &label)
     66 {
     67    mState.mLabel = label;
     68    if (mImpl)
     69    {
     70        return mImpl->onLabelUpdate(context);
     71    }
     72    return angle::Result::Continue;
     73 }
     74 
     75 const std::string &Buffer::getLabel() const
     76 {
     77    return mState.mLabel;
     78 }
     79 
     80 angle::Result Buffer::bufferStorageExternal(Context *context,
     81                                            BufferBinding target,
     82                                            GLsizeiptr size,
     83                                            GLeglClientBufferEXT clientBuffer,
     84                                            GLbitfield flags)
     85 {
     86    return bufferExternalDataImpl(context, target, clientBuffer, size, flags);
     87 }
     88 
     89 angle::Result Buffer::bufferStorage(Context *context,
     90                                    BufferBinding target,
     91                                    GLsizeiptr size,
     92                                    const void *data,
     93                                    GLbitfield flags)
     94 {
     95    return bufferDataImpl(context, target, data, size, BufferUsage::InvalidEnum, flags);
     96 }
     97 
     98 angle::Result Buffer::bufferData(Context *context,
     99                                 BufferBinding target,
    100                                 const void *data,
    101                                 GLsizeiptr size,
    102                                 BufferUsage usage)
    103 {
    104    GLbitfield flags = (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_DYNAMIC_STORAGE_BIT_EXT);
    105    return bufferDataImpl(context, target, data, size, usage, flags);
    106 }
    107 
    108 angle::Result Buffer::bufferDataImpl(Context *context,
    109                                     BufferBinding target,
    110                                     const void *data,
    111                                     GLsizeiptr size,
    112                                     BufferUsage usage,
    113                                     GLbitfield flags)
    114 {
    115    const void *dataForImpl = data;
    116 
    117    if (mState.isMapped())
    118    {
    119        // Per the OpenGL ES 3.0 spec, buffers are implicity unmapped when a call to
    120        // BufferData happens on a mapped buffer:
    121        //
    122        //     If any portion of the buffer object is mapped in the current context or any context
    123        //     current to another thread, it is as though UnmapBuffer (see section 2.10.3) is
    124        //     executed in each such context prior to deleting the existing data store.
    125        //
    126        GLboolean dontCare = GL_FALSE;
    127        ANGLE_TRY(unmap(context, &dontCare));
    128    }
    129 
    130    // If we are using robust resource init, make sure the buffer starts cleared.
    131    // Note: the Context is checked for nullptr because of some testing code.
    132    // TODO(jmadill): Investigate lazier clearing.
    133    if (context && context->isRobustResourceInitEnabled() && !data && size > 0)
    134    {
    135        angle::MemoryBuffer *scratchBuffer = nullptr;
    136        ANGLE_CHECK_GL_ALLOC(
    137            context, context->getZeroFilledBuffer(static_cast<size_t>(size), &scratchBuffer));
    138        dataForImpl = scratchBuffer->data();
    139    }
    140 
    141    if (mImpl->setDataWithUsageFlags(context, target, nullptr, dataForImpl, size, usage, flags) ==
    142        angle::Result::Stop)
    143    {
    144        // If setData fails, the buffer contents are undefined. Set a zero size to indicate that.
    145        mIndexRangeCache.clear();
    146        mState.mSize = 0;
    147 
    148        // Notify when storage changes.
    149        onStateChange(angle::SubjectMessage::SubjectChanged);
    150 
    151        return angle::Result::Stop;
    152    }
    153 
    154    bool wholeBuffer = size == mState.mSize;
    155 
    156    mIndexRangeCache.clear();
    157    mState.mUsage                = usage;
    158    mState.mSize                 = size;
    159    mState.mImmutable            = (usage == BufferUsage::InvalidEnum);
    160    mState.mStorageExtUsageFlags = flags;
    161 
    162    // Notify when storage changes.
    163    if (wholeBuffer)
    164    {
    165        onContentsChange();
    166    }
    167    else
    168    {
    169        onStateChange(angle::SubjectMessage::SubjectChanged);
    170    }
    171 
    172    return angle::Result::Continue;
    173 }
    174 
    175 angle::Result Buffer::bufferExternalDataImpl(Context *context,
    176                                             BufferBinding target,
    177                                             GLeglClientBufferEXT clientBuffer,
    178                                             GLsizeiptr size,
    179                                             GLbitfield flags)
    180 {
    181    if (mState.isMapped())
    182    {
    183        // Per the OpenGL ES 3.0 spec, buffers are implicitly unmapped when a call to
    184        // BufferData happens on a mapped buffer:
    185        //
    186        //     If any portion of the buffer object is mapped in the current context or any context
    187        //     current to another thread, it is as though UnmapBuffer (see section 2.10.3) is
    188        //     executed in each such context prior to deleting the existing data store.
    189        //
    190        GLboolean dontCare = GL_FALSE;
    191        ANGLE_TRY(unmap(context, &dontCare));
    192    }
    193 
    194    if (mImpl->setDataWithUsageFlags(context, target, clientBuffer, nullptr, size,
    195                                     BufferUsage::InvalidEnum, flags) == angle::Result::Stop)
    196    {
    197        // If setData fails, the buffer contents are undefined. Set a zero size to indicate that.
    198        mIndexRangeCache.clear();
    199        mState.mSize = 0;
    200 
    201        // Notify when storage changes.
    202        onStateChange(angle::SubjectMessage::SubjectChanged);
    203 
    204        return angle::Result::Stop;
    205    }
    206 
    207    mIndexRangeCache.clear();
    208    mState.mUsage                = BufferUsage::InvalidEnum;
    209    mState.mSize                 = size;
    210    mState.mImmutable            = GL_TRUE;
    211    mState.mStorageExtUsageFlags = flags;
    212    mState.mExternal             = GL_TRUE;
    213 
    214    // Notify when storage changes.
    215    onStateChange(angle::SubjectMessage::SubjectChanged);
    216 
    217    return angle::Result::Continue;
    218 }
    219 
    220 angle::Result Buffer::bufferSubData(const Context *context,
    221                                    BufferBinding target,
    222                                    const void *data,
    223                                    GLsizeiptr size,
    224                                    GLintptr offset)
    225 {
    226    ANGLE_TRY(mImpl->setSubData(context, target, data, size, offset));
    227 
    228    mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
    229                                     static_cast<unsigned int>(size));
    230 
    231    // Notify when data changes.
    232    onContentsChange();
    233 
    234    return angle::Result::Continue;
    235 }
    236 
    237 angle::Result Buffer::copyBufferSubData(const Context *context,
    238                                        Buffer *source,
    239                                        GLintptr sourceOffset,
    240                                        GLintptr destOffset,
    241                                        GLsizeiptr size)
    242 {
    243    ANGLE_TRY(
    244        mImpl->copySubData(context, source->getImplementation(), sourceOffset, destOffset, size));
    245 
    246    mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset),
    247                                     static_cast<unsigned int>(size));
    248 
    249    // Notify when data changes.
    250    onContentsChange();
    251 
    252    return angle::Result::Continue;
    253 }
    254 
    255 angle::Result Buffer::map(const Context *context, GLenum access)
    256 {
    257    ASSERT(!mState.mMapped);
    258 
    259    mState.mMapPointer = nullptr;
    260    ANGLE_TRY(mImpl->map(context, access, &mState.mMapPointer));
    261 
    262    ASSERT(access == GL_WRITE_ONLY_OES);
    263 
    264    mState.mMapped      = GL_TRUE;
    265    mState.mMapOffset   = 0;
    266    mState.mMapLength   = mState.mSize;
    267    mState.mAccess      = access;
    268    mState.mAccessFlags = GL_MAP_WRITE_BIT;
    269    mIndexRangeCache.clear();
    270 
    271    // Notify when state changes.
    272    onStateChange(angle::SubjectMessage::SubjectMapped);
    273 
    274    return angle::Result::Continue;
    275 }
    276 
    277 angle::Result Buffer::mapRange(const Context *context,
    278                               GLintptr offset,
    279                               GLsizeiptr length,
    280                               GLbitfield access)
    281 {
    282    ASSERT(!mState.mMapped);
    283    ASSERT(offset + length <= mState.mSize);
    284 
    285    mState.mMapPointer = nullptr;
    286    ANGLE_TRY(mImpl->mapRange(context, offset, length, access, &mState.mMapPointer));
    287 
    288    mState.mMapped      = GL_TRUE;
    289    mState.mMapOffset   = static_cast<GLint64>(offset);
    290    mState.mMapLength   = static_cast<GLint64>(length);
    291    mState.mAccess      = GL_WRITE_ONLY_OES;
    292    mState.mAccessFlags = access;
    293 
    294    // The OES_mapbuffer extension states that GL_WRITE_ONLY_OES is the only valid
    295    // value for GL_BUFFER_ACCESS_OES because it was written against ES2.  Since there is
    296    // no update for ES3 and the GL_READ_ONLY and GL_READ_WRITE enums don't exist for ES,
    297    // we cannot properly set GL_BUFFER_ACCESS_OES when glMapBufferRange is called.
    298 
    299    if ((access & GL_MAP_WRITE_BIT) > 0)
    300    {
    301        mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
    302                                         static_cast<unsigned int>(length));
    303    }
    304 
    305    // Notify when state changes.
    306    onStateChange(angle::SubjectMessage::SubjectMapped);
    307 
    308    return angle::Result::Continue;
    309 }
    310 
    311 angle::Result Buffer::unmap(const Context *context, GLboolean *result)
    312 {
    313    ASSERT(mState.mMapped);
    314 
    315    *result = GL_FALSE;
    316    ANGLE_TRY(mImpl->unmap(context, result));
    317 
    318    mState.mMapped      = GL_FALSE;
    319    mState.mMapPointer  = nullptr;
    320    mState.mMapOffset   = 0;
    321    mState.mMapLength   = 0;
    322    mState.mAccess      = GL_WRITE_ONLY_OES;
    323    mState.mAccessFlags = 0;
    324 
    325    // Notify when data changes.
    326    onStateChange(angle::SubjectMessage::SubjectUnmapped);
    327 
    328    return angle::Result::Continue;
    329 }
    330 
    331 void Buffer::onDataChanged()
    332 {
    333    mIndexRangeCache.clear();
    334 
    335    // Notify when data changes.
    336    onContentsChange();
    337 
    338    mImpl->onDataChanged();
    339 }
    340 
    341 angle::Result Buffer::getIndexRange(const gl::Context *context,
    342                                    DrawElementsType type,
    343                                    size_t offset,
    344                                    size_t count,
    345                                    bool primitiveRestartEnabled,
    346                                    IndexRange *outRange) const
    347 {
    348    if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange))
    349    {
    350        return angle::Result::Continue;
    351    }
    352 
    353    ANGLE_TRY(
    354        mImpl->getIndexRange(context, type, offset, count, primitiveRestartEnabled, outRange));
    355 
    356    mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
    357 
    358    return angle::Result::Continue;
    359 }
    360 
    361 GLint64 Buffer::getMemorySize() const
    362 {
    363    GLint64 implSize = mImpl->getMemorySize();
    364    return implSize > 0 ? implSize : mState.mSize;
    365 }
    366 
    367 bool Buffer::isDoubleBoundForTransformFeedback() const
    368 {
    369    return mState.mTransformFeedbackIndexedBindingCount > 1;
    370 }
    371 
    372 void Buffer::onTFBindingChanged(const Context *context, bool bound, bool indexed)
    373 {
    374    ASSERT(bound || mState.mBindingCount > 0);
    375    mState.mBindingCount += bound ? 1 : -1;
    376    if (indexed)
    377    {
    378        ASSERT(bound || mState.mTransformFeedbackIndexedBindingCount > 0);
    379        mState.mTransformFeedbackIndexedBindingCount += bound ? 1 : -1;
    380 
    381        onStateChange(angle::SubjectMessage::BindingChanged);
    382    }
    383    else
    384    {
    385        mState.mTransformFeedbackGenericBindingCount += bound ? 1 : -1;
    386    }
    387 }
    388 
    389 angle::Result Buffer::getSubData(const gl::Context *context,
    390                                 GLintptr offset,
    391                                 GLsizeiptr size,
    392                                 void *outData)
    393 {
    394    return mImpl->getSubData(context, offset, size, outData);
    395 }
    396 
    397 void Buffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
    398 {
    399    // Pass it along!
    400    ASSERT(index == kImplementationSubjectIndex);
    401    ASSERT(message == angle::SubjectMessage::SubjectChanged ||
    402           message == angle::SubjectMessage::InternalMemoryAllocationChanged);
    403    onStateChange(message);
    404 }
    405 
    406 size_t Buffer::getContentsObserverIndex(VertexArray *vertexArray, uint32_t bufferIndex) const
    407 {
    408    for (size_t observerIndex = 0; observerIndex < mContentsObservers.size(); ++observerIndex)
    409    {
    410        const ContentsObserver &observer = mContentsObservers[observerIndex];
    411        if (observer.vertexArray == vertexArray && observer.bufferIndex == bufferIndex)
    412        {
    413            return observerIndex;
    414        }
    415    }
    416 
    417    return kInvalidContentsObserverIndex;
    418 }
    419 
    420 void Buffer::addContentsObserver(VertexArray *vertexArray, uint32_t bufferIndex)
    421 {
    422    if (getContentsObserverIndex(vertexArray, bufferIndex) == kInvalidContentsObserverIndex)
    423    {
    424        mContentsObservers.push_back({vertexArray, bufferIndex});
    425    }
    426 }
    427 
    428 void Buffer::removeContentsObserver(VertexArray *vertexArray, uint32_t bufferIndex)
    429 {
    430    size_t foundObserver = getContentsObserverIndex(vertexArray, bufferIndex);
    431    if (foundObserver != kInvalidContentsObserverIndex)
    432    {
    433        size_t lastObserverIndex = mContentsObservers.size() - 1;
    434        if (foundObserver != lastObserverIndex)
    435        {
    436            mContentsObservers[foundObserver] = mContentsObservers[lastObserverIndex];
    437        }
    438        mContentsObservers.pop_back();
    439    }
    440 }
    441 
    442 void Buffer::onContentsChange()
    443 {
    444    for (const ContentsObserver &observer : mContentsObservers)
    445    {
    446        observer.vertexArray->onBufferContentsChange(observer.bufferIndex);
    447    }
    448 }
    449 }  // namespace gl