Home | History | Annotate | Download | only in geometry
      1 //
      2 // Copyright (c) 2002-2010 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 // geometry/VertexDataManager.h: Defines the VertexDataManager, a class that
      8 // runs the Buffer translation process.
      9 
     10 #include "libGLESv2/geometry/VertexDataManager.h"
     11 
     12 #include "common/debug.h"
     13 
     14 #include "libGLESv2/Buffer.h"
     15 #include "libGLESv2/Program.h"
     16 #include "libGLESv2/main.h"
     17 
     18 #include "libGLESv2/geometry/vertexconversion.h"
     19 #include "libGLESv2/geometry/IndexDataManager.h"
     20 
     21 namespace
     22 {
     23     enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
     24 }
     25 
     26 namespace gl
     27 {
     28 
     29 VertexDataManager::VertexDataManager(Context *context, IDirect3DDevice9 *device) : mContext(context), mDevice(device)
     30 {
     31     for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
     32     {
     33         mDirtyCurrentValue[i] = true;
     34         mCurrentValueBuffer[i] = NULL;
     35     }
     36 
     37     const D3DCAPS9 &caps = context->getDeviceCaps();
     38     checkVertexCaps(caps.DeclTypes);
     39 
     40     mStreamingBuffer = new StreamingVertexBuffer(mDevice, INITIAL_STREAM_BUFFER_SIZE);
     41 }
     42 
     43 VertexDataManager::~VertexDataManager()
     44 {
     45     delete mStreamingBuffer;
     46 
     47     for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
     48     {
     49         delete mCurrentValueBuffer[i];
     50     }
     51 }
     52 
     53 UINT VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
     54 {
     55     Buffer *buffer = attribute.mBoundBuffer.get();
     56 
     57     int inputStride = attribute.stride();
     58     int elementSize = attribute.typeSize();
     59     const FormatConverter &converter = formatConverter(attribute);
     60     UINT streamOffset = 0;
     61 
     62     void *output = NULL;
     63 
     64     if (vertexBuffer)
     65     {
     66         output = vertexBuffer->map(attribute, spaceRequired(attribute, count), &streamOffset);
     67     }
     68 
     69     if (output == NULL)
     70     {
     71         ERR("Failed to map vertex buffer.");
     72         return -1;
     73     }
     74 
     75     const char *input = NULL;
     76 
     77     if (buffer)
     78     {
     79         int offset = attribute.mOffset;
     80 
     81         input = static_cast<const char*>(buffer->data()) + offset;
     82     }
     83     else
     84     {
     85         input = static_cast<const char*>(attribute.mPointer);
     86     }
     87 
     88     input += inputStride * start;
     89 
     90     if (converter.identity && inputStride == elementSize)
     91     {
     92         memcpy(output, input, count * inputStride);
     93     }
     94     else
     95     {
     96         converter.convertArray(input, inputStride, count, output);
     97     }
     98 
     99     vertexBuffer->unmap();
    100 
    101     return streamOffset;
    102 }
    103 
    104 GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)
    105 {
    106     GLenum error = GL_NO_ERROR;
    107     const VertexAttributeArray &attribs = mContext->getVertexAttributes();
    108     Program *program = mContext->getCurrentProgram();
    109 
    110     for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
    111     {
    112         translated[attributeIndex].active = (program->getSemanticIndex(attributeIndex) != -1);
    113     }
    114 
    115     // Determine the required storage size per used buffer
    116     for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    117     {
    118         Buffer *buffer = attribs[i].mBoundBuffer.get();
    119 
    120         if (translated[i].active && attribs[i].mArrayEnabled && (buffer || attribs[i].mPointer))
    121         {
    122             StaticVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
    123 
    124             if (staticBuffer && staticBuffer->size() == 0)
    125             {
    126                 int totalCount = buffer->size() / attribs[i].stride();
    127                 staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount));
    128             }
    129             else if (!staticBuffer || staticBuffer->lookupAttribute(attribs[i]) == -1)
    130             {
    131                 if (mStreamingBuffer)
    132                 {
    133                     mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count));
    134                 }
    135             }
    136         }
    137     }
    138 
    139     // Invalidate static buffers if the attribute formats no longer match
    140     for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    141     {
    142         Buffer *buffer = attribs[i].mBoundBuffer.get();
    143 
    144         if (translated[i].active && attribs[i].mArrayEnabled && buffer)
    145         {
    146             StaticVertexBuffer *staticBuffer = buffer->getVertexBuffer();
    147 
    148             if (staticBuffer && staticBuffer->size() != 0)
    149             {
    150                 bool matchingAttributes = true;
    151 
    152                 for (int j = 0; j < MAX_VERTEX_ATTRIBS; j++)
    153                 {
    154                     if (translated[j].active && attribs[j].mArrayEnabled && attribs[j].mBoundBuffer.get() == buffer)
    155                     {
    156                         if (staticBuffer->lookupAttribute(attribs[j]) == -1)
    157                         {
    158                             matchingAttributes = false;
    159                             break;
    160                         }
    161                     }
    162                 }
    163 
    164                 if (!matchingAttributes && mStreamingBuffer)
    165                 {
    166                     mStreamingBuffer->addRequiredSpaceFor(staticBuffer);
    167                     buffer->invalidateStaticData();
    168                 }
    169             }
    170         }
    171     }
    172 
    173     // Reserve the required space per used buffer
    174     for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    175     {
    176         Buffer *buffer = attribs[i].mBoundBuffer.get();
    177 
    178         if (translated[i].active && attribs[i].mArrayEnabled && (buffer || attribs[i].mPointer))
    179         {
    180             ArrayVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
    181             ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : mStreamingBuffer;
    182 
    183             if (vertexBuffer)
    184             {
    185                 vertexBuffer->reserveRequiredSpace();
    186             }
    187         }
    188     }
    189 
    190     // Perform the vertex data translations
    191     for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    192     {
    193         if (translated[i].active)
    194         {
    195             Buffer *buffer = attribs[i].mBoundBuffer.get();
    196 
    197             if (attribs[i].mArrayEnabled)
    198             {
    199                 if (!buffer && attribs[i].mPointer == NULL)
    200                 {
    201                     // This is an application error that would normally result in a crash, but we catch it and return an error
    202                     ERR("An enabled vertex array has no buffer and no pointer.");
    203                     return GL_INVALID_OPERATION;
    204                 }
    205 
    206                 const FormatConverter &converter = formatConverter(attribs[i]);
    207 
    208                 StaticVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
    209                 ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer);
    210 
    211                 UINT streamOffset = -1;
    212 
    213                 if (staticBuffer)
    214                 {
    215                     streamOffset = staticBuffer->lookupAttribute(attribs[i]);
    216 
    217                     if (streamOffset == -1)
    218                     {
    219                         // Convert the entire buffer
    220                         int totalCount = buffer->size() / attribs[i].stride();
    221                         int startIndex = attribs[i].mOffset / attribs[i].stride();
    222 
    223                         streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i]);
    224                     }
    225 
    226                     if (streamOffset != -1)
    227                     {
    228                         streamOffset += (start + attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize;
    229                     }
    230                 }
    231                 else
    232                 {
    233                     streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);
    234                 }
    235 
    236                 if (streamOffset == -1)
    237                 {
    238                     return GL_OUT_OF_MEMORY;
    239                 }
    240 
    241                 translated[i].vertexBuffer = vertexBuffer->getBuffer();
    242                 translated[i].type = converter.d3dDeclType;
    243                 translated[i].stride = converter.outputElementSize;
    244                 translated[i].offset = streamOffset;
    245             }
    246             else
    247             {
    248                 if (mDirtyCurrentValue[i])
    249                 {
    250                     delete mCurrentValueBuffer[i];
    251                     mCurrentValueBuffer[i] = new ConstantVertexBuffer(mDevice, attribs[i].mCurrentValue[0], attribs[i].mCurrentValue[1], attribs[i].mCurrentValue[2], attribs[i].mCurrentValue[3]);
    252                     mDirtyCurrentValue[i] = false;
    253                 }
    254 
    255                 translated[i].vertexBuffer = mCurrentValueBuffer[i]->getBuffer();
    256 
    257                 translated[i].type = D3DDECLTYPE_FLOAT4;
    258                 translated[i].stride = 0;
    259                 translated[i].offset = 0;
    260             }
    261         }
    262     }
    263 
    264     return GL_NO_ERROR;
    265 }
    266 
    267 std::size_t VertexDataManager::spaceRequired(const VertexAttribute &attrib, std::size_t count) const
    268 {
    269     return formatConverter(attrib).outputElementSize * count;
    270 }
    271 
    272 // Mapping from OpenGL-ES vertex attrib type to D3D decl type:
    273 //
    274 // BYTE                 SHORT (Cast)
    275 // BYTE-norm            FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
    276 // UNSIGNED_BYTE        UBYTE4 (Identity) or SHORT (Cast)
    277 // UNSIGNED_BYTE-norm   UBYTE4N (Identity) or FLOAT (Normalize)
    278 // SHORT                SHORT (Identity)
    279 // SHORT-norm           SHORT-norm (Identity) or FLOAT (Normalize)
    280 // UNSIGNED_SHORT       FLOAT (Cast)
    281 // UNSIGNED_SHORT-norm  USHORT-norm (Identity) or FLOAT (Normalize)
    282 // FIXED (not in WebGL) FLOAT (FixedToFloat)
    283 // FLOAT                FLOAT (Identity)
    284 
    285 // GLToCType maps from GL type (as GLenum) to the C typedef.
    286 template <GLenum GLType> struct GLToCType { };
    287 
    288 template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; };
    289 template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; };
    290 template <> struct GLToCType<GL_SHORT> { typedef GLshort type; };
    291 template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; };
    292 template <> struct GLToCType<GL_FIXED> { typedef GLuint type; };
    293 template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; };
    294 
    295 // This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
    296 enum D3DVertexType
    297 {
    298     D3DVT_FLOAT,
    299     D3DVT_SHORT,
    300     D3DVT_SHORT_NORM,
    301     D3DVT_UBYTE,
    302     D3DVT_UBYTE_NORM,
    303     D3DVT_USHORT_NORM
    304 };
    305 
    306 // D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
    307 template <unsigned int D3DType> struct D3DToCType { };
    308 
    309 template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
    310 template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
    311 template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
    312 template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
    313 template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
    314 template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
    315 
    316 // Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
    317 template <unsigned int type, int size>
    318 struct WidenRule
    319 {
    320 };
    321 
    322 template <int size> struct WidenRule<D3DVT_FLOAT, size>          : gl::NoWiden<size> { };
    323 template <int size> struct WidenRule<D3DVT_SHORT, size>          : gl::WidenToEven<size> { };
    324 template <int size> struct WidenRule<D3DVT_SHORT_NORM, size>     : gl::WidenToEven<size> { };
    325 template <int size> struct WidenRule<D3DVT_UBYTE, size>          : gl::WidenToFour<size> { };
    326 template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size>     : gl::WidenToFour<size> { };
    327 template <int size> struct WidenRule<D3DVT_USHORT_NORM, size>    : gl::WidenToEven<size> { };
    328 
    329 // VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
    330 template <unsigned int d3dtype, int size>
    331 struct VertexTypeFlags
    332 {
    333 };
    334 
    335 template <unsigned int capflag, unsigned int declflag>
    336 struct VertexTypeFlagsHelper
    337 {
    338     enum { capflag = capflag };
    339     enum { declflag = declflag };
    340 };
    341 
    342 template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
    343 template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
    344 template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
    345 template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
    346 template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
    347 template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
    348 template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
    349 template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
    350 template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
    351 template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
    352 template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
    353 template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
    354 
    355 
    356 // VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
    357 template <GLenum GLtype, bool normalized>
    358 struct VertexTypeMapping
    359 {
    360 };
    361 
    362 template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
    363 struct VertexTypeMappingBase
    364 {
    365     enum { preferred = Preferred };
    366     enum { fallback = Fallback };
    367 };
    368 
    369 template <> struct VertexTypeMapping<GL_BYTE, false>                        : VertexTypeMappingBase<D3DVT_SHORT> { };                       // Cast
    370 template <> struct VertexTypeMapping<GL_BYTE, true>                         : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // Normalize
    371 template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false>               : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { };          // Identity, Cast
    372 template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true>                : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { };     // Identity, Normalize
    373 template <> struct VertexTypeMapping<GL_SHORT, false>                       : VertexTypeMappingBase<D3DVT_SHORT> { };                       // Identity
    374 template <> struct VertexTypeMapping<GL_SHORT, true>                        : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { };     // Cast, Normalize
    375 template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false>              : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // Cast
    376 template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true>               : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { };    // Cast, Normalize
    377 template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized>   : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // FixedToFloat
    378 template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized>   : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // Identity
    379 
    380 
    381 // Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
    382 // The conversion rules themselves are defined in vertexconversion.h.
    383 
    384 // Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
    385 template <GLenum fromType, bool normalized, unsigned int toType>
    386 struct ConversionRule : gl::Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type>
    387 {
    388 };
    389 
    390 // All conversions from normalized types to float use the Normalize operator.
    391 template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : gl::Normalize<typename GLToCType<fromType>::type> { };
    392 
    393 // Use a full specialisation for this so that it preferentially matches ahead of the generic normalize-to-float rules.
    394 template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
    395 template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
    396 
    397 // A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
    398 // whether it is normalized or not.
    399 template <class T, bool normalized>
    400 struct DefaultVertexValuesStage2
    401 {
    402 };
    403 
    404 template <class T> struct DefaultVertexValuesStage2<T, true>  : gl::NormalizedDefaultValues<T> { };
    405 template <class T> struct DefaultVertexValuesStage2<T, false> : gl::SimpleDefaultValues<T> { };
    406 
    407 // Work out the default value rule for a D3D type (expressed as the C type) and
    408 template <class T, bool normalized>
    409 struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized>
    410 {
    411 };
    412 
    413 template <bool normalized> struct DefaultVertexValues<float, normalized> : gl::SimpleDefaultValues<float> { };
    414 
    415 // Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
    416 // The fallback conversion produces an output that all D3D9 devices must support.
    417 template <class T> struct UsePreferred { enum { type = T::preferred }; };
    418 template <class T> struct UseFallback { enum { type = T::fallback }; };
    419 
    420 // Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
    421 // it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
    422 // and the D3DDECLTYPE member needed for the vertex declaration in declflag.
    423 template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
    424 struct Converter
    425     : gl::VertexDataConverter<typename GLToCType<fromType>::type,
    426                               WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
    427                               ConversionRule<fromType,
    428                                              normalized,
    429                                              PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
    430                               DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
    431 {
    432 private:
    433     enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
    434     enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
    435 
    436 public:
    437     enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
    438     enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
    439 };
    440 
    441 // Initialise a TranslationInfo
    442 #define TRANSLATION(type, norm, size, preferred)                                    \
    443     {                                                                               \
    444         Converter<type, norm, size, preferred>::identity,                           \
    445         Converter<type, norm, size, preferred>::finalSize,                          \
    446         Converter<type, norm, size, preferred>::convertArray,                       \
    447         static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag)  \
    448     }
    449 
    450 #define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size)    \
    451     {                                                       \
    452         Converter<type, norm, size, UsePreferred>::capflag, \
    453         TRANSLATION(type, norm, size, UsePreferred),        \
    454         TRANSLATION(type, norm, size, UseFallback)          \
    455     }
    456 
    457 #define TRANSLATIONS_FOR_TYPE(type)                                                                                                                                                                         \
    458     {                                                                                                                                                                                                       \
    459         { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
    460         { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) },     \
    461     }
    462 
    463 const VertexDataManager::TranslationDescription VertexDataManager::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
    464 {
    465     TRANSLATIONS_FOR_TYPE(GL_BYTE),
    466     TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
    467     TRANSLATIONS_FOR_TYPE(GL_SHORT),
    468     TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
    469     TRANSLATIONS_FOR_TYPE(GL_FIXED),
    470     TRANSLATIONS_FOR_TYPE(GL_FLOAT)
    471 };
    472 
    473 void VertexDataManager::checkVertexCaps(DWORD declTypes)
    474 {
    475     for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
    476     {
    477         for (unsigned int j = 0; j < 2; j++)
    478         {
    479             for (unsigned int k = 0; k < 4; k++)
    480             {
    481                 if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0)
    482                 {
    483                     mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion;
    484                 }
    485                 else
    486                 {
    487                     mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion;
    488                 }
    489             }
    490         }
    491     }
    492 }
    493 
    494 // This is used to index mAttributeTypes and mPossibleTranslations.
    495 unsigned int VertexDataManager::typeIndex(GLenum type) const
    496 {
    497     switch (type)
    498     {
    499       case GL_BYTE: return 0;
    500       case GL_UNSIGNED_BYTE: return 1;
    501       case GL_SHORT: return 2;
    502       case GL_UNSIGNED_SHORT: return 3;
    503       case GL_FIXED: return 4;
    504       case GL_FLOAT: return 5;
    505 
    506       default: UNREACHABLE(); return 5;
    507     }
    508 }
    509 
    510 void VertexDataManager::setupAttributes(const TranslatedAttribute *attributes)
    511 {
    512     D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS];
    513     D3DVERTEXELEMENT9 *element = &elements[0];
    514 
    515     for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    516     {
    517         if (attributes[i].active)
    518         {
    519             mDevice->SetStreamSource(i, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride);
    520 
    521             element->Stream = i;
    522             element->Offset = 0;
    523             element->Type = attributes[i].type;
    524             element->Method = D3DDECLMETHOD_DEFAULT;
    525             element->Usage = D3DDECLUSAGE_TEXCOORD;
    526             element->UsageIndex = attributes[i].semanticIndex;
    527             element++;
    528         }
    529     }
    530 
    531     static const D3DVERTEXELEMENT9 end = D3DDECL_END();
    532     *element = end;
    533 
    534     IDirect3DVertexDeclaration9 *vertexDeclaration;
    535     mDevice->CreateVertexDeclaration(elements, &vertexDeclaration);
    536     mDevice->SetVertexDeclaration(vertexDeclaration);
    537     vertexDeclaration->Release();
    538 }
    539 
    540 VertexBuffer::VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : mDevice(device), mVertexBuffer(NULL)
    541 {
    542     if (size > 0)
    543     {
    544         D3DPOOL pool = getDisplay()->getBufferPool(usageFlags);
    545         HRESULT result = device->CreateVertexBuffer(size, usageFlags, 0, pool, &mVertexBuffer, NULL);
    546 
    547         if (FAILED(result))
    548         {
    549             ERR("Out of memory allocating a vertex buffer of size %lu.", size);
    550         }
    551     }
    552 }
    553 
    554 VertexBuffer::~VertexBuffer()
    555 {
    556     if (mVertexBuffer)
    557     {
    558         mVertexBuffer->Release();
    559     }
    560 }
    561 
    562 void VertexBuffer::unmap()
    563 {
    564     if (mVertexBuffer)
    565     {
    566         mVertexBuffer->Unlock();
    567     }
    568 }
    569 
    570 IDirect3DVertexBuffer9 *VertexBuffer::getBuffer() const
    571 {
    572     return mVertexBuffer;
    573 }
    574 
    575 ConstantVertexBuffer::ConstantVertexBuffer(IDirect3DDevice9 *device, float x, float y, float z, float w) : VertexBuffer(device, 4 * sizeof(float), D3DUSAGE_WRITEONLY)
    576 {
    577     void *buffer = NULL;
    578 
    579     if (mVertexBuffer)
    580     {
    581         HRESULT result = mVertexBuffer->Lock(0, 0, &buffer, 0);
    582 
    583         if (FAILED(result))
    584         {
    585             ERR("Lock failed with error 0x%08x", result);
    586         }
    587     }
    588 
    589     if (buffer)
    590     {
    591         float *vector = (float*)buffer;
    592 
    593         vector[0] = x;
    594         vector[1] = y;
    595         vector[2] = z;
    596         vector[3] = w;
    597 
    598         mVertexBuffer->Unlock();
    599     }
    600 }
    601 
    602 ConstantVertexBuffer::~ConstantVertexBuffer()
    603 {
    604 }
    605 
    606 ArrayVertexBuffer::ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : VertexBuffer(device, size, usageFlags)
    607 {
    608     mBufferSize = size;
    609     mWritePosition = 0;
    610     mRequiredSpace = 0;
    611 }
    612 
    613 ArrayVertexBuffer::~ArrayVertexBuffer()
    614 {
    615 }
    616 
    617 void ArrayVertexBuffer::addRequiredSpace(UINT requiredSpace)
    618 {
    619     mRequiredSpace += requiredSpace;
    620 }
    621 
    622 void ArrayVertexBuffer::addRequiredSpaceFor(ArrayVertexBuffer *buffer)
    623 {
    624     mRequiredSpace += buffer->mRequiredSpace;
    625 }
    626 
    627 StreamingVertexBuffer::StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize) : ArrayVertexBuffer(device, initialSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)
    628 {
    629 }
    630 
    631 StreamingVertexBuffer::~StreamingVertexBuffer()
    632 {
    633 }
    634 
    635 void *StreamingVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *offset)
    636 {
    637     void *mapPtr = NULL;
    638 
    639     if (mVertexBuffer)
    640     {
    641         HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
    642 
    643         if (FAILED(result))
    644         {
    645             ERR("Lock failed with error 0x%08x", result);
    646             return NULL;
    647         }
    648 
    649         *offset = mWritePosition;
    650         mWritePosition += requiredSpace;
    651     }
    652 
    653     return mapPtr;
    654 }
    655 
    656 void StreamingVertexBuffer::reserveRequiredSpace()
    657 {
    658     if (mRequiredSpace > mBufferSize)
    659     {
    660         if (mVertexBuffer)
    661         {
    662             mVertexBuffer->Release();
    663             mVertexBuffer = NULL;
    664         }
    665 
    666         mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2);   // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations.
    667 
    668         D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
    669         HRESULT result = mDevice->CreateVertexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL);
    670 
    671         if (FAILED(result))
    672         {
    673             ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
    674         }
    675 
    676         mWritePosition = 0;
    677     }
    678     else if (mWritePosition + mRequiredSpace > mBufferSize)   // Recycle
    679     {
    680         if (mVertexBuffer)
    681         {
    682             void *dummy;
    683             mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
    684             mVertexBuffer->Unlock();
    685         }
    686 
    687         mWritePosition = 0;
    688     }
    689 
    690     mRequiredSpace = 0;
    691 }
    692 
    693 StaticVertexBuffer::StaticVertexBuffer(IDirect3DDevice9 *device) : ArrayVertexBuffer(device, 0, D3DUSAGE_WRITEONLY)
    694 {
    695 }
    696 
    697 StaticVertexBuffer::~StaticVertexBuffer()
    698 {
    699 }
    700 
    701 void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, UINT *streamOffset)
    702 {
    703     void *mapPtr = NULL;
    704 
    705     if (mVertexBuffer)
    706     {
    707         HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, 0);
    708 
    709         if (FAILED(result))
    710         {
    711             ERR("Lock failed with error 0x%08x", result);
    712             return NULL;
    713         }
    714 
    715         int attributeOffset = attribute.mOffset % attribute.stride();
    716         VertexElement element = {attribute.mType, attribute.mSize, attribute.mNormalized, attributeOffset, mWritePosition};
    717         mCache.push_back(element);
    718 
    719         *streamOffset = mWritePosition;
    720         mWritePosition += requiredSpace;
    721     }
    722 
    723     return mapPtr;
    724 }
    725 
    726 void StaticVertexBuffer::reserveRequiredSpace()
    727 {
    728     if (!mVertexBuffer && mBufferSize == 0)
    729     {
    730         D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY);
    731         HRESULT result = mDevice->CreateVertexBuffer(mRequiredSpace, D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL);
    732 
    733         if (FAILED(result))
    734         {
    735             ERR("Out of memory allocating a vertex buffer of size %lu.", mRequiredSpace);
    736         }
    737 
    738         mBufferSize = mRequiredSpace;
    739     }
    740     else if (mVertexBuffer && mBufferSize >= mRequiredSpace)
    741     {
    742         // Already allocated
    743     }
    744     else UNREACHABLE();   // Static vertex buffers can't be resized
    745 
    746     mRequiredSpace = 0;
    747 }
    748 
    749 UINT StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
    750 {
    751     for (unsigned int element = 0; element < mCache.size(); element++)
    752     {
    753         if (mCache[element].type == attribute.mType &&  mCache[element].size == attribute.mSize && mCache[element].normalized == attribute.mNormalized)
    754         {
    755             if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride())
    756             {
    757                 return mCache[element].streamOffset;
    758             }
    759         }
    760     }
    761 
    762     return -1;
    763 }
    764 
    765 const VertexDataManager::FormatConverter &VertexDataManager::formatConverter(const VertexAttribute &attribute) const
    766 {
    767     return mAttributeTypes[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1];
    768 }
    769 }
    770