Home | History | Annotate | Download | only in d3d
      1 //
      2 // Copyright (c) 2002-2012 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 // VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface
      8 // class with derivations, classes that perform graphics API agnostic vertex buffer operations.
      9 
     10 #include "libGLESv2/renderer/d3d/VertexBuffer.h"
     11 #include "libGLESv2/renderer/d3d/BufferD3D.h"
     12 #include "libGLESv2/renderer/Renderer.h"
     13 #include "libGLESv2/VertexAttribute.h"
     14 
     15 #include "common/mathutil.h"
     16 
     17 namespace rx
     18 {
     19 
     20 unsigned int VertexBuffer::mNextSerial = 1;
     21 
     22 VertexBuffer::VertexBuffer()
     23 {
     24     updateSerial();
     25 }
     26 
     27 VertexBuffer::~VertexBuffer()
     28 {
     29 }
     30 
     31 void VertexBuffer::updateSerial()
     32 {
     33     mSerial = mNextSerial++;
     34 }
     35 
     36 unsigned int VertexBuffer::getSerial() const
     37 {
     38     return mSerial;
     39 }
     40 
     41 VertexBufferInterface::VertexBufferInterface(rx::Renderer *renderer, bool dynamic) : mRenderer(renderer)
     42 {
     43     mDynamic = dynamic;
     44     mWritePosition = 0;
     45     mReservedSpace = 0;
     46 
     47     mVertexBuffer = renderer->createVertexBuffer();
     48 }
     49 
     50 VertexBufferInterface::~VertexBufferInterface()
     51 {
     52     delete mVertexBuffer;
     53 }
     54 
     55 unsigned int VertexBufferInterface::getSerial() const
     56 {
     57     return mVertexBuffer->getSerial();
     58 }
     59 
     60 unsigned int VertexBufferInterface::getBufferSize() const
     61 {
     62     return mVertexBuffer->getBufferSize();
     63 }
     64 
     65 gl::Error VertexBufferInterface::setBufferSize(unsigned int size)
     66 {
     67     if (mVertexBuffer->getBufferSize() == 0)
     68     {
     69         return mVertexBuffer->initialize(size, mDynamic);
     70     }
     71     else
     72     {
     73         return mVertexBuffer->setBufferSize(size);
     74     }
     75 }
     76 
     77 unsigned int VertexBufferInterface::getWritePosition() const
     78 {
     79     return mWritePosition;
     80 }
     81 
     82 void VertexBufferInterface::setWritePosition(unsigned int writePosition)
     83 {
     84     mWritePosition = writePosition;
     85 }
     86 
     87 gl::Error VertexBufferInterface::discard()
     88 {
     89     return mVertexBuffer->discard();
     90 }
     91 
     92 gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
     93                                                        GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset)
     94 {
     95     gl::Error error(GL_NO_ERROR);
     96 
     97     unsigned int spaceRequired;
     98     error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired);
     99     if (error.isError())
    100     {
    101         return error;
    102     }
    103 
    104     if (mWritePosition + spaceRequired < mWritePosition)
    105     {
    106         return gl::Error(GL_OUT_OF_MEMORY, "Internal error, new vertex buffer write position would overflow.");
    107     }
    108 
    109     error = reserveSpace(mReservedSpace);
    110     if (error.isError())
    111     {
    112         return error;
    113     }
    114     mReservedSpace = 0;
    115 
    116     error = mVertexBuffer->storeVertexAttributes(attrib, currentValue, start, count, instances, mWritePosition);
    117     if (error.isError())
    118     {
    119         return error;
    120     }
    121 
    122     if (outStreamOffset)
    123     {
    124         *outStreamOffset = mWritePosition;
    125     }
    126 
    127     mWritePosition += spaceRequired;
    128 
    129     // Align to 16-byte boundary
    130     mWritePosition = rx::roundUp(mWritePosition, 16u);
    131 
    132     return gl::Error(GL_NO_ERROR);
    133 }
    134 
    135 gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances)
    136 {
    137     gl::Error error(GL_NO_ERROR);
    138 
    139     unsigned int requiredSpace;
    140     error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &requiredSpace);
    141     if (error.isError())
    142     {
    143         return error;
    144     }
    145 
    146     // Protect against integer overflow
    147     if (mReservedSpace + requiredSpace < mReservedSpace)
    148     {
    149         return gl::Error(GL_OUT_OF_MEMORY, "Unable to reserve %u extra bytes in internal vertex buffer, "
    150                          "it would result in an overflow.", requiredSpace);
    151     }
    152 
    153     mReservedSpace += requiredSpace;
    154 
    155     // Align to 16-byte boundary
    156     mReservedSpace = rx::roundUp(mReservedSpace, 16u);
    157 
    158     return gl::Error(GL_NO_ERROR);
    159 }
    160 
    161 VertexBuffer* VertexBufferInterface::getVertexBuffer() const
    162 {
    163     return mVertexBuffer;
    164 }
    165 
    166 bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib,
    167                                                   const gl::VertexAttribCurrentValueData &currentValue) const
    168 {
    169     gl::Buffer *buffer = attrib.buffer.get();
    170     BufferD3D *storage = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL;
    171 
    172     if (!storage || !storage->supportsDirectBinding())
    173     {
    174         return false;
    175     }
    176 
    177     // Alignment restrictions: In D3D, vertex data must be aligned to
    178     //  the format stride, or to a 4-byte boundary, whichever is smaller.
    179     //  (Undocumented, and experimentally confirmed)
    180     size_t alignment = 4;
    181     bool requiresConversion = false;
    182 
    183     if (attrib.type != GL_FLOAT)
    184     {
    185         gl::VertexFormat vertexFormat(attrib, currentValue.Type);
    186 
    187         unsigned int outputElementSize;
    188         getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize);
    189         alignment = std::min<size_t>(outputElementSize, 4);
    190 
    191         requiresConversion = (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0;
    192     }
    193 
    194     bool isAligned = (static_cast<size_t>(ComputeVertexAttributeStride(attrib)) % alignment == 0) &&
    195                      (static_cast<size_t>(attrib.offset) % alignment == 0);
    196 
    197     return !requiresConversion && isAligned;
    198 }
    199 
    200 StreamingVertexBufferInterface::StreamingVertexBufferInterface(rx::Renderer *renderer, std::size_t initialSize) : VertexBufferInterface(renderer, true)
    201 {
    202     setBufferSize(initialSize);
    203 }
    204 
    205 StreamingVertexBufferInterface::~StreamingVertexBufferInterface()
    206 {
    207 }
    208 
    209 gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size)
    210 {
    211     unsigned int curBufferSize = getBufferSize();
    212     if (size > curBufferSize)
    213     {
    214         gl::Error error = setBufferSize(std::max(size, 3 * curBufferSize / 2));
    215         if (error.isError())
    216         {
    217             return error;
    218         }
    219         setWritePosition(0);
    220     }
    221     else if (getWritePosition() + size > curBufferSize)
    222     {
    223         gl::Error error = discard();
    224         if (error.isError())
    225         {
    226             return error;
    227         }
    228         setWritePosition(0);
    229     }
    230 
    231     return gl::Error(GL_NO_ERROR);
    232 }
    233 
    234 StaticVertexBufferInterface::StaticVertexBufferInterface(rx::Renderer *renderer) : VertexBufferInterface(renderer, false)
    235 {
    236 }
    237 
    238 StaticVertexBufferInterface::~StaticVertexBufferInterface()
    239 {
    240 }
    241 
    242 bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attrib, unsigned int *outStreamOffset)
    243 {
    244     for (unsigned int element = 0; element < mCache.size(); element++)
    245     {
    246         if (mCache[element].type == attrib.type &&
    247             mCache[element].size == attrib.size &&
    248             mCache[element].stride == ComputeVertexAttributeStride(attrib) &&
    249             mCache[element].normalized == attrib.normalized &&
    250             mCache[element].pureInteger == attrib.pureInteger)
    251         {
    252             size_t offset = (static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib));
    253             if (mCache[element].attributeOffset == offset)
    254             {
    255                 if (outStreamOffset)
    256                 {
    257                     *outStreamOffset = mCache[element].streamOffset;
    258                 }
    259                 return true;
    260             }
    261         }
    262     }
    263 
    264     return false;
    265 }
    266 
    267 gl::Error StaticVertexBufferInterface::reserveSpace(unsigned int size)
    268 {
    269     unsigned int curSize = getBufferSize();
    270     if (curSize == 0)
    271     {
    272         return setBufferSize(size);
    273     }
    274     else if (curSize >= size)
    275     {
    276         return gl::Error(GL_NO_ERROR);
    277     }
    278     else
    279     {
    280         UNREACHABLE();
    281         return gl::Error(GL_INVALID_OPERATION, "Internal error, Static vertex buffers can't be resized.");
    282     }
    283 }
    284 
    285 gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
    286                                                              GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset)
    287 {
    288     unsigned int streamOffset;
    289     gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValue, start, count, instances, &streamOffset);
    290     if (error.isError())
    291     {
    292         return error;
    293     }
    294 
    295     size_t attributeOffset = static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib);
    296     VertexElement element = { attrib.type, attrib.size, ComputeVertexAttributeStride(attrib), attrib.normalized, attrib.pureInteger, attributeOffset, streamOffset };
    297     mCache.push_back(element);
    298 
    299     if (outStreamOffset)
    300     {
    301         *outStreamOffset = streamOffset;
    302     }
    303 
    304     return gl::Error(GL_NO_ERROR);
    305 }
    306 
    307 }
    308