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     intptr_t offset = reinterpret_cast<intptr_t>(indices);
    119     bool alignedOffset = false;
    120 
    121     BufferStorage *storage = NULL;
    122 
    123     if (buffer != NULL)
    124     {
    125         storage = buffer->getStorage();
    126 
    127         switch (type)
    128         {
    129           case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
    130           case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
    131           case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
    132           default: UNREACHABLE(); alignedOffset = false;
    133         }
    134 
    135         if (gl::ComputeTypeSize(type) * count + offset > static_cast<GLsizei>(storage->getSize()))
    136         {
    137             return GL_INVALID_OPERATION;
    138         }
    139 
    140         indices = static_cast<const GLubyte*>(storage->getData()) + offset;
    141     }
    142 
    143     StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
    144 
    145     StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
    146     IndexBufferInterface *indexBuffer = streamingBuffer;
    147     bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
    148                          destinationIndexType == type;
    149     UINT streamOffset = 0;
    150 
    151     if (directStorage)
    152     {
    153         indexBuffer = streamingBuffer;
    154         streamOffset = offset;
    155         storage->markBufferUsage();
    156 
    157         if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
    158                                                      &translated->maxIndex, NULL))
    159         {
    160             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
    161             buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
    162                                                    translated->maxIndex, offset);
    163         }
    164     }
    165     else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
    166     {
    167         indexBuffer = staticBuffer;
    168         if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
    169                                                            &translated->maxIndex, &streamOffset))
    170         {
    171             streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
    172             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
    173             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
    174                                                          translated->maxIndex, streamOffset);
    175         }
    176     }
    177     else
    178     {
    179         int convertCount = count;
    180 
    181         if (staticBuffer)
    182         {
    183             if (staticBuffer->getBufferSize() == 0 && alignedOffset)
    184             {
    185                 indexBuffer = staticBuffer;
    186                 convertCount = storage->getSize() / gl::ComputeTypeSize(type);
    187             }
    188             else
    189             {
    190                 buffer->invalidateStaticData();
    191                 staticBuffer = NULL;
    192             }
    193         }
    194 
    195         if (!indexBuffer)
    196         {
    197             ERR("No valid index buffer.");
    198             return GL_INVALID_OPERATION;
    199         }
    200 
    201         unsigned int bufferSizeRequired = convertCount * gl::ComputeTypeSize(destinationIndexType);
    202         indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
    203 
    204         void* output = NULL;
    205         streamOffset = indexBuffer->mapBuffer(bufferSizeRequired, &output);
    206         if (streamOffset == -1 || output == NULL)
    207         {
    208             ERR("Failed to map index buffer.");
    209             return GL_OUT_OF_MEMORY;
    210         }
    211 
    212         convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
    213 
    214         if (!indexBuffer->unmapBuffer())
    215         {
    216             ERR("Failed to unmap index buffer.");
    217             return GL_OUT_OF_MEMORY;
    218         }
    219 
    220         computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
    221 
    222         if (staticBuffer)
    223         {
    224             streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
    225             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
    226                                                          translated->maxIndex, streamOffset);
    227         }
    228     }
    229 
    230     translated->storage = directStorage ? storage : NULL;
    231     translated->indexBuffer = indexBuffer->getIndexBuffer();
    232     translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
    233     translated->startIndex = streamOffset / gl::ComputeTypeSize(destinationIndexType);
    234     translated->startOffset = streamOffset;
    235 
    236     if (buffer)
    237     {
    238         buffer->promoteStaticUsage(count * gl::ComputeTypeSize(type));
    239     }
    240 
    241     return GL_NO_ERROR;
    242 }
    243 
    244 StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
    245 {
    246     if (count <= 65536)   // 16-bit indices
    247     {
    248         const unsigned int spaceNeeded = count * sizeof(unsigned short);
    249 
    250         if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
    251         {
    252             delete mCountingBuffer;
    253             mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
    254             mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
    255 
    256             void* mappedMemory = NULL;
    257             if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
    258             {
    259                 ERR("Failed to map counting buffer.");
    260                 return NULL;
    261             }
    262 
    263             unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
    264             for(int i = 0; i < count; i++)
    265             {
    266                 data[i] = i;
    267             }
    268 
    269             if (!mCountingBuffer->unmapBuffer())
    270             {
    271                 ERR("Failed to unmap counting buffer.");
    272                 return NULL;
    273             }
    274         }
    275     }
    276     else if (mStreamingBufferInt)   // 32-bit indices supported
    277     {
    278         const unsigned int spaceNeeded = count * sizeof(unsigned int);
    279 
    280         if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
    281         {
    282             delete mCountingBuffer;
    283             mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
    284             mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
    285 
    286             void* mappedMemory = NULL;
    287             if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
    288             {
    289                 ERR("Failed to map counting buffer.");
    290                 return NULL;
    291             }
    292 
    293             unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
    294             for(int i = 0; i < count; i++)
    295             {
    296                 data[i] = i;
    297             }
    298 
    299             if (!mCountingBuffer->unmapBuffer())
    300             {
    301                 ERR("Failed to unmap counting buffer.");
    302                 return NULL;
    303             }
    304         }
    305     }
    306     else
    307     {
    308         return NULL;
    309     }
    310 
    311     return mCountingBuffer;
    312 }
    313 
    314 }
    315