Home | History | Annotate | Download | only in renderer
      1 #include "precompiled.h"
      2 //
      3 // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style license that can be
      5 // found in the LICENSE file.
      6 //
      7 
      8 // IndexDataManager.cpp: Defines the IndexDataManager, a class that
      9 // runs the Buffer translation process for index buffers.
     10 
     11 #include "libGLESv2/renderer/IndexDataManager.h"
     12 #include "libGLESv2/renderer/BufferStorage.h"
     13 
     14 #include "libGLESv2/Buffer.h"
     15 #include "libGLESv2/main.h"
     16 #include "libGLESv2/formatutils.h"
     17 #include "libGLESv2/renderer/IndexBuffer.h"
     18 #include "libGLESv2/renderer/Renderer.h"
     19 
     20 namespace rx
     21 {
     22 
     23 IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
     24 {
     25     mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
     26     if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
     27     {
     28         delete mStreamingBufferShort;
     29         mStreamingBufferShort = NULL;
     30     }
     31 
     32     mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
     33     if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
     34     {
     35         delete mStreamingBufferInt;
     36         mStreamingBufferInt = NULL;
     37     }
     38 
     39     if (!mStreamingBufferShort)
     40     {
     41         // Make sure both buffers are deleted.
     42         delete mStreamingBufferInt;
     43         mStreamingBufferInt = NULL;
     44 
     45         ERR("Failed to allocate the streaming index buffer(s).");
     46     }
     47 
     48     mCountingBuffer = NULL;
     49 }
     50 
     51 IndexDataManager::~IndexDataManager()
     52 {
     53     delete mStreamingBufferShort;
     54     delete mStreamingBufferInt;
     55     delete mCountingBuffer;
     56 }
     57 
     58 static void convertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
     59 {
     60     if (sourceType == GL_UNSIGNED_BYTE)
     61     {
     62         ASSERT(destinationType == GL_UNSIGNED_SHORT);
     63         const GLubyte *in = static_cast<const GLubyte*>(input);
     64         GLushort *out = static_cast<GLushort*>(output);
     65 
     66         for (GLsizei i = 0; i < count; i++)
     67         {
     68             out[i] = in[i];
     69         }
     70     }
     71     else if (sourceType == GL_UNSIGNED_INT)
     72     {
     73         ASSERT(destinationType == GL_UNSIGNED_INT);
     74         memcpy(output, input, count * sizeof(GLuint));
     75     }
     76     else if (sourceType == GL_UNSIGNED_SHORT)
     77     {
     78         if (destinationType == GL_UNSIGNED_SHORT)
     79         {
     80             memcpy(output, input, count * sizeof(GLushort));
     81         }
     82         else if (destinationType == GL_UNSIGNED_INT)
     83         {
     84             const GLushort *in = static_cast<const GLushort*>(input);
     85             GLuint *out = static_cast<GLuint*>(output);
     86 
     87             for (GLsizei i = 0; i < count; i++)
     88             {
     89                 out[i] = in[i];
     90             }
     91         }
     92         else UNREACHABLE();
     93     }
     94     else UNREACHABLE();
     95 }
     96 
     97 template <class IndexType>
     98 static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
     99 {
    100     *minIndex = indices[0];
    101     *maxIndex = indices[0];
    102 
    103     for (GLsizei i = 0; i < count; i++)
    104     {
    105         if (*minIndex > indices[i]) *minIndex = indices[i];
    106         if (*maxIndex < indices[i]) *maxIndex = indices[i];
    107     }
    108 }
    109 
    110 static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
    111 {
    112     if (type == GL_UNSIGNED_BYTE)
    113     {
    114         computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
    115     }
    116     else if (type == GL_UNSIGNED_INT)
    117     {
    118         computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
    119     }
    120     else if (type == GL_UNSIGNED_SHORT)
    121     {
    122         computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
    123     }
    124     else UNREACHABLE();
    125 }
    126 
    127 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
    128 {
    129     if (!mStreamingBufferShort)
    130     {
    131         return GL_OUT_OF_MEMORY;
    132     }
    133 
    134     GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
    135     unsigned int offset = 0;
    136     bool alignedOffset = false;
    137 
    138     BufferStorage *storage = NULL;
    139 
    140     if (buffer != NULL)
    141     {
    142         if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
    143         {
    144             return GL_OUT_OF_MEMORY;
    145         }
    146         offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
    147 
    148         storage = buffer->getStorage();
    149 
    150         switch (type)
    151         {
    152           case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
    153           case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
    154           case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
    155           default: UNREACHABLE(); alignedOffset = false;
    156         }
    157 
    158         unsigned int typeSize = gl::GetTypeBytes(type);
    159 
    160         // check for integer overflows
    161         if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeSize) ||
    162             typeSize * static_cast<unsigned int>(count) + offset < offset)
    163         {
    164             return GL_OUT_OF_MEMORY;
    165         }
    166 
    167         if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize())
    168         {
    169             return GL_INVALID_OPERATION;
    170         }
    171 
    172         indices = static_cast<const GLubyte*>(storage->getData()) + offset;
    173     }
    174 
    175     StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
    176     IndexBufferInterface *indexBuffer = NULL;
    177     bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
    178                          destinationIndexType == type;
    179     unsigned int streamOffset = 0;
    180 
    181     if (directStorage)
    182     {
    183         streamOffset = offset;
    184 
    185         if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
    186             &translated->maxIndex, NULL))
    187         {
    188             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
    189             buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
    190                                                    translated->maxIndex, offset);
    191         }
    192     }
    193     else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
    194     {
    195         indexBuffer = staticBuffer;
    196 
    197         if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
    198                                                            &translated->maxIndex, &streamOffset))
    199         {
    200             streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
    201             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
    202             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
    203                                                          translated->maxIndex, streamOffset);
    204         }
    205     }
    206     else
    207     {
    208         computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
    209     }
    210 
    211     // Avoid D3D11's primitive restart index value
    212     // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
    213     if (translated->maxIndex == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3)
    214     {
    215         destinationIndexType = GL_UNSIGNED_INT;
    216         directStorage = false;
    217         indexBuffer = NULL;
    218     }
    219 
    220     if (!directStorage && !indexBuffer)
    221     {
    222         indexBuffer = (destinationIndexType == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
    223 
    224         unsigned int convertCount = count;
    225 
    226         if (staticBuffer)
    227         {
    228             if (staticBuffer->getBufferSize() == 0 && alignedOffset)
    229             {
    230                 indexBuffer = staticBuffer;
    231                 convertCount = storage->getSize() / gl::GetTypeBytes(type);
    232             }
    233             else
    234             {
    235                 buffer->invalidateStaticData();
    236                 staticBuffer = NULL;
    237             }
    238         }
    239 
    240         if (!indexBuffer)
    241         {
    242             ERR("No valid index buffer.");
    243             return GL_INVALID_OPERATION;
    244         }
    245 
    246         unsigned int indexTypeSize = gl::GetTypeBytes(destinationIndexType);
    247         if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize)
    248         {
    249             ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize);
    250             return GL_OUT_OF_MEMORY;
    251         }
    252 
    253         unsigned int bufferSizeRequired = convertCount * indexTypeSize;
    254         if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
    255         {
    256             ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
    257             return GL_OUT_OF_MEMORY;
    258         }
    259 
    260         void* output = NULL;
    261         if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
    262         {
    263             ERR("Failed to map index buffer.");
    264             return GL_OUT_OF_MEMORY;
    265         }
    266 
    267         convertIndices(type, destinationIndexType, staticBuffer ? storage->getData() : indices, convertCount, output);
    268 
    269         if (!indexBuffer->unmapBuffer())
    270         {
    271             ERR("Failed to unmap index buffer.");
    272             return GL_OUT_OF_MEMORY;
    273         }
    274 
    275         if (staticBuffer)
    276         {
    277             streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
    278             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
    279                                                          translated->maxIndex, streamOffset);
    280         }
    281     }
    282 
    283     translated->storage = directStorage ? storage : NULL;
    284     translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
    285     translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
    286     translated->startIndex = streamOffset / gl::GetTypeBytes(destinationIndexType);
    287     translated->startOffset = streamOffset;
    288     translated->indexType = destinationIndexType;
    289 
    290     if (buffer)
    291     {
    292         buffer->promoteStaticUsage(count * gl::GetTypeBytes(type));
    293     }
    294 
    295     return GL_NO_ERROR;
    296 }
    297 
    298 StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
    299 {
    300     if (count <= 65536)   // 16-bit indices
    301     {
    302         const unsigned int spaceNeeded = count * sizeof(unsigned short);
    303 
    304         if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
    305         {
    306             delete mCountingBuffer;
    307             mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
    308             mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
    309 
    310             void* mappedMemory = NULL;
    311             if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
    312             {
    313                 ERR("Failed to map counting buffer.");
    314                 return NULL;
    315             }
    316 
    317             unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
    318             for(int i = 0; i < count; i++)
    319             {
    320                 data[i] = i;
    321             }
    322 
    323             if (!mCountingBuffer->unmapBuffer())
    324             {
    325                 ERR("Failed to unmap counting buffer.");
    326                 return NULL;
    327             }
    328         }
    329     }
    330     else if (mStreamingBufferInt)   // 32-bit indices supported
    331     {
    332         const unsigned int spaceNeeded = count * sizeof(unsigned int);
    333 
    334         if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
    335         {
    336             delete mCountingBuffer;
    337             mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
    338             mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
    339 
    340             void* mappedMemory = NULL;
    341             if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
    342             {
    343                 ERR("Failed to map counting buffer.");
    344                 return NULL;
    345             }
    346 
    347             unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
    348             for(int i = 0; i < count; i++)
    349             {
    350                 data[i] = i;
    351             }
    352 
    353             if (!mCountingBuffer->unmapBuffer())
    354             {
    355                 ERR("Failed to unmap counting buffer.");
    356                 return NULL;
    357             }
    358         }
    359     }
    360     else
    361     {
    362         return NULL;
    363     }
    364 
    365     return mCountingBuffer;
    366 }
    367 
    368 }
    369