tor-browser

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

VertexDataManager.cpp (24631B)


      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 // VertexDataManager.h: Defines the VertexDataManager, a class that
      8 // runs the Buffer translation process.
      9 
     10 #include "libANGLE/renderer/d3d/VertexDataManager.h"
     11 
     12 #include "common/bitset_utils.h"
     13 #include "libANGLE/Buffer.h"
     14 #include "libANGLE/Context.h"
     15 #include "libANGLE/Program.h"
     16 #include "libANGLE/State.h"
     17 #include "libANGLE/VertexArray.h"
     18 #include "libANGLE/VertexAttribute.h"
     19 #include "libANGLE/formatutils.h"
     20 #include "libANGLE/renderer/d3d/BufferD3D.h"
     21 #include "libANGLE/renderer/d3d/ContextD3D.h"
     22 #include "libANGLE/renderer/d3d/VertexBuffer.h"
     23 
     24 using namespace angle;
     25 
     26 namespace rx
     27 {
     28 namespace
     29 {
     30 enum
     31 {
     32    INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024
     33 };
     34 // This has to be at least 4k or else it fails on ATI cards.
     35 enum
     36 {
     37    CONSTANT_VERTEX_BUFFER_SIZE = 4096
     38 };
     39 
     40 // Warning: ensure the binding matches attrib.bindingIndex before using these functions.
     41 int64_t GetMaxAttributeByteOffsetForDraw(const gl::VertexAttribute &attrib,
     42                                         const gl::VertexBinding &binding,
     43                                         int64_t elementCount)
     44 {
     45    CheckedNumeric<int64_t> stride = ComputeVertexAttributeStride(attrib, binding);
     46    CheckedNumeric<int64_t> offset = ComputeVertexAttributeOffset(attrib, binding);
     47    CheckedNumeric<int64_t> size   = ComputeVertexAttributeTypeSize(attrib);
     48 
     49    ASSERT(elementCount > 0);
     50 
     51    CheckedNumeric<int64_t> result =
     52        stride * (CheckedNumeric<int64_t>(elementCount) - 1) + size + offset;
     53    return result.ValueOrDefault(std::numeric_limits<int64_t>::max());
     54 }
     55 
     56 // Warning: ensure the binding matches attrib.bindingIndex before using these functions.
     57 int ElementsInBuffer(const gl::VertexAttribute &attrib,
     58                     const gl::VertexBinding &binding,
     59                     unsigned int size)
     60 {
     61    angle::CheckedNumeric<int64_t> bufferSize(size);
     62    angle::CheckedNumeric<int64_t> stride      = ComputeVertexAttributeStride(attrib, binding);
     63    angle::CheckedNumeric<int64_t> offset      = ComputeVertexAttributeOffset(attrib, binding);
     64    angle::CheckedNumeric<int64_t> elementSize = ComputeVertexAttributeTypeSize(attrib);
     65 
     66    auto elementsInBuffer    = (bufferSize - (offset % stride) + (stride - elementSize)) / stride;
     67    auto elementsInBufferInt = elementsInBuffer.Cast<int>();
     68 
     69    return elementsInBufferInt.ValueOrDefault(0);
     70 }
     71 
     72 // Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
     73 bool DirectStoragePossible(const gl::Context *context,
     74                           const gl::VertexAttribute &attrib,
     75                           const gl::VertexBinding &binding)
     76 {
     77    // Current value attribs may not use direct storage.
     78    if (!attrib.enabled)
     79    {
     80        return false;
     81    }
     82 
     83    gl::Buffer *buffer = binding.getBuffer().get();
     84    if (!buffer)
     85    {
     86        return false;
     87    }
     88 
     89    BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
     90    ASSERT(bufferD3D);
     91    if (!bufferD3D->supportsDirectBinding())
     92    {
     93        return false;
     94    }
     95 
     96    // Alignment restrictions: In D3D, vertex data must be aligned to the format stride, or to a
     97    // 4-byte boundary, whichever is smaller. (Undocumented, and experimentally confirmed)
     98    size_t alignment = 4;
     99 
    100    // TODO(jmadill): add VertexFormatCaps
    101    BufferFactoryD3D *factory = bufferD3D->getFactory();
    102 
    103    angle::FormatID vertexFormatID = attrib.format->id;
    104 
    105    // CPU-converted vertex data must be converted (naturally).
    106    if ((factory->getVertexConversionType(vertexFormatID) & VERTEX_CONVERT_CPU) != 0)
    107    {
    108        return false;
    109    }
    110 
    111    if (attrib.format->vertexAttribType != gl::VertexAttribType::Float)
    112    {
    113        unsigned int elementSize = 0;
    114        angle::Result error =
    115            factory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &elementSize);
    116        ASSERT(error == angle::Result::Continue);
    117        alignment = std::min<size_t>(elementSize, 4);
    118    }
    119 
    120    GLintptr offset = ComputeVertexAttributeOffset(attrib, binding);
    121    // Final alignment check - unaligned data must be converted.
    122    return (static_cast<size_t>(ComputeVertexAttributeStride(attrib, binding)) % alignment == 0) &&
    123           (static_cast<size_t>(offset) % alignment == 0);
    124 }
    125 }  // anonymous namespace
    126 
    127 TranslatedAttribute::TranslatedAttribute()
    128    : active(false),
    129      attribute(nullptr),
    130      binding(nullptr),
    131      currentValueType(gl::VertexAttribType::InvalidEnum),
    132      baseOffset(0),
    133      usesFirstVertexOffset(false),
    134      stride(0),
    135      vertexBuffer(),
    136      storage(nullptr),
    137      serial(0),
    138      divisor(0)
    139 {}
    140 
    141 TranslatedAttribute::TranslatedAttribute(const TranslatedAttribute &other) = default;
    142 
    143 angle::Result TranslatedAttribute::computeOffset(const gl::Context *context,
    144                                                 GLint startVertex,
    145                                                 unsigned int *offsetOut) const
    146 {
    147    if (!usesFirstVertexOffset)
    148    {
    149        *offsetOut = baseOffset;
    150        return angle::Result::Continue;
    151    }
    152 
    153    CheckedNumeric<unsigned int> offset(baseOffset);
    154    CheckedNumeric<unsigned int> checkedStride(stride);
    155 
    156    offset += checkedStride * static_cast<unsigned int>(startVertex);
    157    ANGLE_CHECK_GL_MATH(GetImplAs<ContextD3D>(context), offset.IsValid());
    158    *offsetOut = offset.ValueOrDie();
    159    return angle::Result::Continue;
    160 }
    161 
    162 // Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
    163 VertexStorageType ClassifyAttributeStorage(const gl::Context *context,
    164                                           const gl::VertexAttribute &attrib,
    165                                           const gl::VertexBinding &binding)
    166 {
    167    // If attribute is disabled, we use the current value.
    168    if (!attrib.enabled)
    169    {
    170        return VertexStorageType::CURRENT_VALUE;
    171    }
    172 
    173    // If specified with immediate data, we must use dynamic storage.
    174    gl::Buffer *buffer = binding.getBuffer().get();
    175    if (!buffer)
    176    {
    177        return VertexStorageType::DYNAMIC;
    178    }
    179 
    180    // Check if the buffer supports direct storage.
    181    if (DirectStoragePossible(context, attrib, binding))
    182    {
    183        return VertexStorageType::DIRECT;
    184    }
    185 
    186    // Otherwise the storage is static or dynamic.
    187    BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
    188    ASSERT(bufferD3D);
    189    switch (bufferD3D->getUsage())
    190    {
    191        case D3DBufferUsage::DYNAMIC:
    192            return VertexStorageType::DYNAMIC;
    193        case D3DBufferUsage::STATIC:
    194            return VertexStorageType::STATIC;
    195        default:
    196            UNREACHABLE();
    197            return VertexStorageType::UNKNOWN;
    198    }
    199 }
    200 
    201 VertexDataManager::CurrentValueState::CurrentValueState(BufferFactoryD3D *factory)
    202    : buffer(new StreamingVertexBufferInterface(factory)), offset(0)
    203 {
    204    data.Values.FloatValues[0] = std::numeric_limits<float>::quiet_NaN();
    205    data.Values.FloatValues[1] = std::numeric_limits<float>::quiet_NaN();
    206    data.Values.FloatValues[2] = std::numeric_limits<float>::quiet_NaN();
    207    data.Values.FloatValues[3] = std::numeric_limits<float>::quiet_NaN();
    208    data.Type                  = gl::VertexAttribType::Float;
    209 }
    210 
    211 VertexDataManager::CurrentValueState::CurrentValueState(CurrentValueState &&other)
    212 {
    213    std::swap(buffer, other.buffer);
    214    std::swap(data, other.data);
    215    std::swap(offset, other.offset);
    216 }
    217 
    218 VertexDataManager::CurrentValueState::~CurrentValueState() {}
    219 
    220 VertexDataManager::VertexDataManager(BufferFactoryD3D *factory)
    221    : mFactory(factory), mStreamingBuffer(factory)
    222 {
    223    mCurrentValueCache.reserve(gl::MAX_VERTEX_ATTRIBS);
    224    for (int currentValueIndex = 0; currentValueIndex < gl::MAX_VERTEX_ATTRIBS; ++currentValueIndex)
    225    {
    226        mCurrentValueCache.emplace_back(factory);
    227    }
    228 }
    229 
    230 VertexDataManager::~VertexDataManager() {}
    231 
    232 angle::Result VertexDataManager::initialize(const gl::Context *context)
    233 {
    234    return mStreamingBuffer.initialize(context, INITIAL_STREAM_BUFFER_SIZE);
    235 }
    236 
    237 void VertexDataManager::deinitialize()
    238 {
    239    mStreamingBuffer.reset();
    240    mCurrentValueCache.clear();
    241 }
    242 
    243 angle::Result VertexDataManager::prepareVertexData(
    244    const gl::Context *context,
    245    GLint start,
    246    GLsizei count,
    247    std::vector<TranslatedAttribute> *translatedAttribs,
    248    GLsizei instances)
    249 {
    250    const gl::State &state                  = context->getState();
    251    const gl::ProgramExecutable *executable = state.getProgramExecutable();
    252    const gl::VertexArray *vertexArray      = state.getVertexArray();
    253    const auto &vertexAttributes            = vertexArray->getVertexAttributes();
    254    const auto &vertexBindings              = vertexArray->getVertexBindings();
    255 
    256    mDynamicAttribsMaskCache.reset();
    257 
    258    translatedAttribs->clear();
    259 
    260    for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex)
    261    {
    262        // Skip attrib locations the program doesn't use.
    263        if (!executable->isAttribLocationActive(attribIndex))
    264            continue;
    265 
    266        const auto &attrib  = vertexAttributes[attribIndex];
    267        const auto &binding = vertexBindings[attrib.bindingIndex];
    268 
    269        // Resize automatically puts in empty attribs
    270        translatedAttribs->resize(attribIndex + 1);
    271 
    272        TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex];
    273        auto currentValueData           = state.getVertexAttribCurrentValue(attribIndex);
    274 
    275        // Record the attribute now
    276        translated->active           = true;
    277        translated->attribute        = &attrib;
    278        translated->binding          = &binding;
    279        translated->currentValueType = currentValueData.Type;
    280        translated->divisor          = binding.getDivisor();
    281 
    282        switch (ClassifyAttributeStorage(context, attrib, binding))
    283        {
    284            case VertexStorageType::STATIC:
    285            {
    286                // Store static attribute.
    287                ANGLE_TRY(StoreStaticAttrib(context, translated));
    288                break;
    289            }
    290            case VertexStorageType::DYNAMIC:
    291                // Dynamic attributes must be handled together.
    292                mDynamicAttribsMaskCache.set(attribIndex);
    293                break;
    294            case VertexStorageType::DIRECT:
    295                // Update translated data for direct attributes.
    296                StoreDirectAttrib(context, translated);
    297                break;
    298            case VertexStorageType::CURRENT_VALUE:
    299            {
    300                ANGLE_TRY(storeCurrentValue(context, currentValueData, translated, attribIndex));
    301                break;
    302            }
    303            default:
    304                UNREACHABLE();
    305                break;
    306        }
    307    }
    308 
    309    if (mDynamicAttribsMaskCache.none())
    310    {
    311        return angle::Result::Continue;
    312    }
    313 
    314    // prepareVertexData is only called by Renderer9 which don't support baseInstance
    315    ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start,
    316                                  count, instances, 0u));
    317 
    318    PromoteDynamicAttribs(context, *translatedAttribs, mDynamicAttribsMaskCache, count);
    319 
    320    return angle::Result::Continue;
    321 }
    322 
    323 // static
    324 void VertexDataManager::StoreDirectAttrib(const gl::Context *context,
    325                                          TranslatedAttribute *directAttrib)
    326 {
    327    ASSERT(directAttrib->attribute && directAttrib->binding);
    328    const auto &attrib  = *directAttrib->attribute;
    329    const auto &binding = *directAttrib->binding;
    330 
    331    gl::Buffer *buffer = binding.getBuffer().get();
    332    ASSERT(buffer);
    333    BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
    334 
    335    ASSERT(DirectStoragePossible(context, attrib, binding));
    336    directAttrib->vertexBuffer.set(nullptr);
    337    directAttrib->storage = bufferD3D;
    338    directAttrib->serial  = bufferD3D->getSerial();
    339    directAttrib->stride = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding));
    340    directAttrib->baseOffset =
    341        static_cast<unsigned int>(ComputeVertexAttributeOffset(attrib, binding));
    342 
    343    // Instanced vertices do not apply the 'start' offset
    344    directAttrib->usesFirstVertexOffset = (binding.getDivisor() == 0);
    345 }
    346 
    347 // static
    348 angle::Result VertexDataManager::StoreStaticAttrib(const gl::Context *context,
    349                                                   TranslatedAttribute *translated)
    350 {
    351    ASSERT(translated->attribute && translated->binding);
    352    const auto &attrib  = *translated->attribute;
    353    const auto &binding = *translated->binding;
    354 
    355    gl::Buffer *buffer = binding.getBuffer().get();
    356    ASSERT(buffer && attrib.enabled && !DirectStoragePossible(context, attrib, binding));
    357    BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
    358 
    359    // Compute source data pointer
    360    const uint8_t *sourceData = nullptr;
    361    const int offset          = static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
    362 
    363    ANGLE_TRY(bufferD3D->getData(context, &sourceData));
    364 
    365    if (sourceData)
    366    {
    367        sourceData += offset;
    368    }
    369 
    370    unsigned int streamOffset = 0;
    371 
    372    translated->storage = nullptr;
    373    ANGLE_TRY(bufferD3D->getFactory()->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0,
    374                                                              &translated->stride));
    375 
    376    auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib, binding);
    377    ASSERT(staticBuffer);
    378 
    379    if (staticBuffer->empty())
    380    {
    381        // Convert the entire buffer
    382        int totalCount =
    383            ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize()));
    384        int startIndex = offset / static_cast<int>(ComputeVertexAttributeStride(attrib, binding));
    385 
    386        if (totalCount > 0)
    387        {
    388            ANGLE_TRY(staticBuffer->storeStaticAttribute(context, attrib, binding, -startIndex,
    389                                                         totalCount, 0, sourceData));
    390        }
    391    }
    392 
    393    unsigned int firstElementOffset =
    394        (static_cast<unsigned int>(offset) /
    395         static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding))) *
    396        translated->stride;
    397 
    398    VertexBuffer *vertexBuffer = staticBuffer->getVertexBuffer();
    399 
    400    CheckedNumeric<unsigned int> checkedOffset(streamOffset);
    401    checkedOffset += firstElementOffset;
    402 
    403    ANGLE_CHECK_GL_MATH(GetImplAs<ContextD3D>(context), checkedOffset.IsValid());
    404 
    405    translated->vertexBuffer.set(vertexBuffer);
    406    translated->serial     = vertexBuffer->getSerial();
    407    translated->baseOffset = streamOffset + firstElementOffset;
    408 
    409    // Instanced vertices do not apply the 'start' offset
    410    translated->usesFirstVertexOffset = (binding.getDivisor() == 0);
    411 
    412    return angle::Result::Continue;
    413 }
    414 
    415 angle::Result VertexDataManager::storeDynamicAttribs(
    416    const gl::Context *context,
    417    std::vector<TranslatedAttribute> *translatedAttribs,
    418    const gl::AttributesMask &dynamicAttribsMask,
    419    GLint start,
    420    size_t count,
    421    GLsizei instances,
    422    GLuint baseInstance)
    423 {
    424    // Instantiating this class will ensure the streaming buffer is never left mapped.
    425    class StreamingBufferUnmapper final : NonCopyable
    426    {
    427      public:
    428        StreamingBufferUnmapper(StreamingVertexBufferInterface *streamingBuffer)
    429            : mStreamingBuffer(streamingBuffer)
    430        {
    431            ASSERT(mStreamingBuffer);
    432        }
    433        ~StreamingBufferUnmapper() { mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); }
    434 
    435      private:
    436        StreamingVertexBufferInterface *mStreamingBuffer;
    437    };
    438 
    439    // Will trigger unmapping on return.
    440    StreamingBufferUnmapper localUnmapper(&mStreamingBuffer);
    441 
    442    // Reserve the required space for the dynamic buffers.
    443    for (auto attribIndex : dynamicAttribsMask)
    444    {
    445        const auto &dynamicAttrib = (*translatedAttribs)[attribIndex];
    446        ANGLE_TRY(
    447            reserveSpaceForAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
    448    }
    449 
    450    // Store dynamic attributes
    451    for (auto attribIndex : dynamicAttribsMask)
    452    {
    453        auto *dynamicAttrib = &(*translatedAttribs)[attribIndex];
    454        ANGLE_TRY(
    455            storeDynamicAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
    456    }
    457 
    458    return angle::Result::Continue;
    459 }
    460 
    461 void VertexDataManager::PromoteDynamicAttribs(
    462    const gl::Context *context,
    463    const std::vector<TranslatedAttribute> &translatedAttribs,
    464    const gl::AttributesMask &dynamicAttribsMask,
    465    size_t count)
    466 {
    467    for (auto attribIndex : dynamicAttribsMask)
    468    {
    469        const auto &dynamicAttrib = translatedAttribs[attribIndex];
    470        ASSERT(dynamicAttrib.attribute && dynamicAttrib.binding);
    471        const auto &binding = *dynamicAttrib.binding;
    472 
    473        gl::Buffer *buffer = binding.getBuffer().get();
    474        if (buffer)
    475        {
    476            // Note: this multiplication can overflow. It should not be a security problem.
    477            BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
    478            size_t typeSize      = ComputeVertexAttributeTypeSize(*dynamicAttrib.attribute);
    479            bufferD3D->promoteStaticUsage(context, count * typeSize);
    480        }
    481    }
    482 }
    483 
    484 angle::Result VertexDataManager::reserveSpaceForAttrib(const gl::Context *context,
    485                                                       const TranslatedAttribute &translatedAttrib,
    486                                                       GLint start,
    487                                                       size_t count,
    488                                                       GLsizei instances,
    489                                                       GLuint baseInstance)
    490 {
    491    ASSERT(translatedAttrib.attribute && translatedAttrib.binding);
    492    const auto &attrib  = *translatedAttrib.attribute;
    493    const auto &binding = *translatedAttrib.binding;
    494 
    495    ASSERT(!DirectStoragePossible(context, attrib, binding));
    496 
    497    gl::Buffer *buffer   = binding.getBuffer().get();
    498    BufferD3D *bufferD3D = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
    499    ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib, binding) == nullptr);
    500 
    501    size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count,
    502                                                             static_cast<size_t>(instances));
    503    // TODO(jiajia.qin@intel.com): force the index buffer to clamp any out of range indices instead
    504    // of invalid operation here.
    505    if (bufferD3D)
    506    {
    507        // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
    508        // a non-instanced draw call
    509        GLint firstVertexIndex = binding.getDivisor() > 0
    510                                     ? UnsignedCeilDivide(baseInstance, binding.getDivisor())
    511                                     : start;
    512        int64_t maxVertexCount =
    513            static_cast<int64_t>(firstVertexIndex) + static_cast<int64_t>(totalCount);
    514 
    515        int64_t maxByte = GetMaxAttributeByteOffsetForDraw(attrib, binding, maxVertexCount);
    516 
    517        ASSERT(bufferD3D->getSize() <= static_cast<size_t>(std::numeric_limits<int64_t>::max()));
    518        ANGLE_CHECK(GetImplAs<ContextD3D>(context),
    519                    maxByte <= static_cast<int64_t>(bufferD3D->getSize()),
    520                    "Vertex buffer is not big enough for the draw call.", GL_INVALID_OPERATION);
    521    }
    522    return mStreamingBuffer.reserveVertexSpace(context, attrib, binding, totalCount, instances,
    523                                               baseInstance);
    524 }
    525 
    526 angle::Result VertexDataManager::storeDynamicAttrib(const gl::Context *context,
    527                                                    TranslatedAttribute *translated,
    528                                                    GLint start,
    529                                                    size_t count,
    530                                                    GLsizei instances,
    531                                                    GLuint baseInstance)
    532 {
    533    ASSERT(translated->attribute && translated->binding);
    534    const auto &attrib  = *translated->attribute;
    535    const auto &binding = *translated->binding;
    536 
    537    gl::Buffer *buffer = binding.getBuffer().get();
    538    ASSERT(buffer || attrib.pointer);
    539    ASSERT(attrib.enabled);
    540 
    541    BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
    542 
    543    // Instanced vertices do not apply the 'start' offset
    544    GLint firstVertexIndex =
    545        (binding.getDivisor() > 0 ? UnsignedCeilDivide(baseInstance, binding.getDivisor()) : start);
    546 
    547    // Compute source data pointer
    548    const uint8_t *sourceData = nullptr;
    549 
    550    if (buffer)
    551    {
    552        ANGLE_TRY(storage->getData(context, &sourceData));
    553        sourceData += static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
    554    }
    555    else
    556    {
    557        // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
    558        // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
    559        sourceData = static_cast<const uint8_t *>(attrib.pointer);
    560    }
    561 
    562    unsigned int streamOffset = 0;
    563 
    564    translated->storage = nullptr;
    565    ANGLE_TRY(
    566        mFactory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &translated->stride));
    567 
    568    size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count,
    569                                                             static_cast<size_t>(instances));
    570 
    571    ANGLE_TRY(mStreamingBuffer.storeDynamicAttribute(
    572        context, attrib, binding, translated->currentValueType, firstVertexIndex,
    573        static_cast<GLsizei>(totalCount), instances, baseInstance, &streamOffset, sourceData));
    574 
    575    VertexBuffer *vertexBuffer = mStreamingBuffer.getVertexBuffer();
    576 
    577    translated->vertexBuffer.set(vertexBuffer);
    578    translated->serial                = vertexBuffer->getSerial();
    579    translated->baseOffset            = streamOffset;
    580    translated->usesFirstVertexOffset = false;
    581 
    582    return angle::Result::Continue;
    583 }
    584 
    585 angle::Result VertexDataManager::storeCurrentValue(
    586    const gl::Context *context,
    587    const gl::VertexAttribCurrentValueData &currentValue,
    588    TranslatedAttribute *translated,
    589    size_t attribIndex)
    590 {
    591    CurrentValueState *cachedState         = &mCurrentValueCache[attribIndex];
    592    StreamingVertexBufferInterface &buffer = *cachedState->buffer;
    593 
    594    if (buffer.getBufferSize() == 0)
    595    {
    596        ANGLE_TRY(buffer.initialize(context, CONSTANT_VERTEX_BUFFER_SIZE));
    597    }
    598 
    599    if (cachedState->data != currentValue)
    600    {
    601        ASSERT(translated->attribute && translated->binding);
    602        const auto &attrib  = *translated->attribute;
    603        const auto &binding = *translated->binding;
    604 
    605        ANGLE_TRY(buffer.reserveVertexSpace(context, attrib, binding, 1, 0, 0));
    606 
    607        const uint8_t *sourceData =
    608            reinterpret_cast<const uint8_t *>(currentValue.Values.FloatValues);
    609        unsigned int streamOffset;
    610        ANGLE_TRY(buffer.storeDynamicAttribute(context, attrib, binding, currentValue.Type, 0, 1, 0,
    611                                               0, &streamOffset, sourceData));
    612 
    613        buffer.getVertexBuffer()->hintUnmapResource();
    614 
    615        cachedState->data   = currentValue;
    616        cachedState->offset = streamOffset;
    617    }
    618 
    619    translated->vertexBuffer.set(buffer.getVertexBuffer());
    620 
    621    translated->storage               = nullptr;
    622    translated->serial                = buffer.getSerial();
    623    translated->divisor               = 0;
    624    translated->stride                = 0;
    625    translated->baseOffset            = static_cast<unsigned int>(cachedState->offset);
    626    translated->usesFirstVertexOffset = false;
    627 
    628    return angle::Result::Continue;
    629 }
    630 
    631 // VertexBufferBinding implementation
    632 VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) {}
    633 
    634 VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other)
    635    : mBoundVertexBuffer(other.mBoundVertexBuffer)
    636 {
    637    if (mBoundVertexBuffer)
    638    {
    639        mBoundVertexBuffer->addRef();
    640    }
    641 }
    642 
    643 VertexBufferBinding::~VertexBufferBinding()
    644 {
    645    if (mBoundVertexBuffer)
    646    {
    647        mBoundVertexBuffer->release();
    648    }
    649 }
    650 
    651 VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other)
    652 {
    653    mBoundVertexBuffer = other.mBoundVertexBuffer;
    654    if (mBoundVertexBuffer)
    655    {
    656        mBoundVertexBuffer->addRef();
    657    }
    658    return *this;
    659 }
    660 
    661 void VertexBufferBinding::set(VertexBuffer *vertexBuffer)
    662 {
    663    if (mBoundVertexBuffer == vertexBuffer)
    664        return;
    665 
    666    if (mBoundVertexBuffer)
    667    {
    668        mBoundVertexBuffer->release();
    669    }
    670    if (vertexBuffer)
    671    {
    672        vertexBuffer->addRef();
    673    }
    674 
    675    mBoundVertexBuffer = vertexBuffer;
    676 }
    677 
    678 VertexBuffer *VertexBufferBinding::get() const
    679 {
    680    return mBoundVertexBuffer;
    681 }
    682 
    683 }  // namespace rx