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