Home | History | Annotate | Download | only in d3d
      1 //
      2 // Copyright (c) 2002-2014 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 // IndexDataManager.cpp: Defines the IndexDataManager, a class that
      8 // runs the Buffer translation process for index buffers.
      9 
     10 #include "libGLESv2/renderer/d3d/IndexDataManager.h"
     11 #include "libGLESv2/renderer/d3d/BufferD3D.h"
     12 #include "libGLESv2/renderer/d3d/IndexBuffer.h"
     13 #include "libGLESv2/renderer/Renderer.h"
     14 #include "libGLESv2/Buffer.h"
     15 #include "libGLESv2/main.h"
     16 #include "libGLESv2/formatutils.h"
     17 
     18 namespace rx
     19 {
     20 
     21 static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
     22 {
     23     if (sourceType == GL_UNSIGNED_BYTE)
     24     {
     25         ASSERT(destinationType == GL_UNSIGNED_SHORT);
     26         const GLubyte *in = static_cast<const GLubyte*>(input);
     27         GLushort *out = static_cast<GLushort*>(output);
     28 
     29         for (GLsizei i = 0; i < count; i++)
     30         {
     31             out[i] = in[i];
     32         }
     33     }
     34     else if (sourceType == GL_UNSIGNED_INT)
     35     {
     36         ASSERT(destinationType == GL_UNSIGNED_INT);
     37         memcpy(output, input, count * sizeof(GLuint));
     38     }
     39     else if (sourceType == GL_UNSIGNED_SHORT)
     40     {
     41         if (destinationType == GL_UNSIGNED_SHORT)
     42         {
     43             memcpy(output, input, count * sizeof(GLushort));
     44         }
     45         else if (destinationType == GL_UNSIGNED_INT)
     46         {
     47             const GLushort *in = static_cast<const GLushort*>(input);
     48             GLuint *out = static_cast<GLuint*>(output);
     49 
     50             for (GLsizei i = 0; i < count; i++)
     51             {
     52                 out[i] = in[i];
     53             }
     54         }
     55         else UNREACHABLE();
     56     }
     57     else UNREACHABLE();
     58 }
     59 
     60 IndexDataManager::IndexDataManager(Renderer *renderer)
     61     : mRenderer(renderer),
     62       mStreamingBufferShort(NULL),
     63       mStreamingBufferInt(NULL)
     64 {
     65 }
     66 
     67 IndexDataManager::~IndexDataManager()
     68 {
     69     SafeDelete(mStreamingBufferShort);
     70     SafeDelete(mStreamingBufferInt);
     71 }
     72 
     73 gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
     74 {
     75     const gl::Type &typeInfo = gl::GetTypeInfo(type);
     76 
     77     GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
     78 
     79     unsigned int offset = 0;
     80     bool alignedOffset = false;
     81 
     82     BufferD3D *storage = NULL;
     83 
     84     if (buffer != NULL)
     85     {
     86         offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
     87 
     88         storage = BufferD3D::makeBufferD3D(buffer->getImplementation());
     89 
     90         switch (type)
     91         {
     92           case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
     93           case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
     94           case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
     95           default: UNREACHABLE(); alignedOffset = false;
     96         }
     97 
     98         ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize());
     99 
    100         indices = static_cast<const GLubyte*>(storage->getData()) + offset;
    101     }
    102 
    103     StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
    104     IndexBufferInterface *indexBuffer = NULL;
    105     bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
    106                          destinationIndexType == type;
    107     unsigned int streamOffset = 0;
    108 
    109     if (directStorage)
    110     {
    111         streamOffset = offset;
    112 
    113         if (!buffer->getIndexRangeCache()->findRange(type, offset, count, NULL, NULL))
    114         {
    115             buffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, offset);
    116         }
    117     }
    118     else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
    119     {
    120         indexBuffer = staticBuffer;
    121 
    122         if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, NULL, &streamOffset))
    123         {
    124             streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes;
    125             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
    126         }
    127     }
    128 
    129     // Avoid D3D11's primitive restart index value
    130     // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
    131     if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3)
    132     {
    133         destinationIndexType = GL_UNSIGNED_INT;
    134         directStorage = false;
    135         indexBuffer = NULL;
    136     }
    137 
    138     const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
    139 
    140     if (!directStorage && !indexBuffer)
    141     {
    142         gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer);
    143         if (error.isError())
    144         {
    145             return error;
    146         }
    147 
    148         unsigned int convertCount = count;
    149 
    150         if (staticBuffer)
    151         {
    152             if (staticBuffer->getBufferSize() == 0 && alignedOffset)
    153             {
    154                 indexBuffer = staticBuffer;
    155                 convertCount = storage->getSize() / typeInfo.bytes;
    156             }
    157             else
    158             {
    159                 storage->invalidateStaticData();
    160                 staticBuffer = NULL;
    161             }
    162         }
    163 
    164         ASSERT(indexBuffer);
    165 
    166         if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes)
    167         {
    168             return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
    169                              convertCount, destTypeInfo.bytes);
    170         }
    171 
    172         unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes;
    173         error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
    174         if (error.isError())
    175         {
    176             return error;
    177         }
    178 
    179         void* output = NULL;
    180         error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset);
    181         if (error.isError())
    182         {
    183             return error;
    184         }
    185 
    186         ConvertIndices(type, destinationIndexType, staticBuffer ? storage->getData() : indices, convertCount, output);
    187 
    188         error = indexBuffer->unmapBuffer();
    189         if (error.isError())
    190         {
    191             return error;
    192         }
    193 
    194         if (staticBuffer)
    195         {
    196             streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes;
    197             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
    198         }
    199     }
    200 
    201     translated->storage = directStorage ? storage : NULL;
    202     translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
    203     translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
    204     translated->startIndex = streamOffset / destTypeInfo.bytes;
    205     translated->startOffset = streamOffset;
    206     translated->indexType = destinationIndexType;
    207 
    208     if (storage)
    209     {
    210         storage->promoteStaticUsage(count * typeInfo.bytes);
    211     }
    212 
    213     return gl::Error(GL_NO_ERROR);
    214 }
    215 
    216 gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer)
    217 {
    218     ASSERT(outBuffer);
    219     if (destinationIndexType == GL_UNSIGNED_INT)
    220     {
    221         if (!mStreamingBufferInt)
    222         {
    223             mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
    224             gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
    225             if (error.isError())
    226             {
    227                 SafeDelete(mStreamingBufferInt);
    228                 return error;
    229             }
    230         }
    231 
    232         *outBuffer = mStreamingBufferInt;
    233         return gl::Error(GL_NO_ERROR);
    234     }
    235     else
    236     {
    237         ASSERT(destinationIndexType == GL_UNSIGNED_SHORT);
    238 
    239         if (!mStreamingBufferShort)
    240         {
    241             mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
    242             gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
    243             if (error.isError())
    244             {
    245                 SafeDelete(mStreamingBufferShort);
    246                 return error;
    247             }
    248         }
    249 
    250         *outBuffer = mStreamingBufferShort;
    251         return gl::Error(GL_NO_ERROR);
    252     }
    253 }
    254 
    255 }
    256