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 // VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation.
      9 
     10 #include "libGLESv2/renderer/VertexBuffer9.h"
     11 #include "libGLESv2/renderer/vertexconversion.h"
     12 #include "libGLESv2/renderer/BufferStorage.h"
     13 #include "libGLESv2/Context.h"
     14 #include "libGLESv2/renderer/Renderer9.h"
     15 
     16 #include "libGLESv2/Buffer.h"
     17 
     18 namespace rx
     19 {
     20 
     21 bool VertexBuffer9::mTranslationsInitialized = false;
     22 VertexBuffer9::FormatConverter VertexBuffer9::mFormatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4];
     23 
     24 VertexBuffer9::VertexBuffer9(rx::Renderer9 *const renderer) : mRenderer(renderer)
     25 {
     26     mVertexBuffer = NULL;
     27     mBufferSize = 0;
     28     mDynamicUsage = false;
     29 
     30     if (!mTranslationsInitialized)
     31     {
     32         initializeTranslations(renderer->getCapsDeclTypes());
     33         mTranslationsInitialized = true;
     34     }
     35 }
     36 
     37 VertexBuffer9::~VertexBuffer9()
     38 {
     39     if (mVertexBuffer)
     40     {
     41         mVertexBuffer->Release();
     42         mVertexBuffer = NULL;
     43     }
     44 }
     45 
     46 bool VertexBuffer9::initialize(unsigned int size, bool dynamicUsage)
     47 {
     48     if (mVertexBuffer)
     49     {
     50         mVertexBuffer->Release();
     51         mVertexBuffer = NULL;
     52     }
     53 
     54     updateSerial();
     55 
     56     if (size > 0)
     57     {
     58         DWORD flags = D3DUSAGE_WRITEONLY;
     59         if (dynamicUsage)
     60         {
     61             flags |= D3DUSAGE_DYNAMIC;
     62         }
     63 
     64         HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer);
     65 
     66         if (FAILED(result))
     67         {
     68             ERR("Out of memory allocating a vertex buffer of size %lu.", size);
     69             return false;
     70         }
     71     }
     72 
     73     mBufferSize = size;
     74     mDynamicUsage = dynamicUsage;
     75     return true;
     76 }
     77 
     78 VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer)
     79 {
     80     ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer));
     81     return static_cast<VertexBuffer9*>(vertexBuffer);
     82 }
     83 
     84 bool VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count,
     85                                              GLsizei instances, unsigned int offset)
     86 {
     87     if (mVertexBuffer)
     88     {
     89         gl::Buffer *buffer = attrib.mBoundBuffer.get();
     90 
     91         int inputStride = attrib.stride();
     92         int elementSize = attrib.typeSize();
     93         const FormatConverter &converter = formatConverter(attrib);
     94 
     95         DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0;
     96 
     97         void *mapPtr = NULL;
     98         HRESULT result = mVertexBuffer->Lock(offset, spaceRequired(attrib, count, instances), &mapPtr, lockFlags);
     99 
    100         if (FAILED(result))
    101         {
    102             ERR("Lock failed with error 0x%08x", result);
    103             return false;
    104         }
    105 
    106         const char *input = NULL;
    107         if (buffer)
    108         {
    109             BufferStorage *storage = buffer->getStorage();
    110             input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.mOffset);
    111         }
    112         else
    113         {
    114             input = static_cast<const char*>(attrib.mPointer);
    115         }
    116 
    117         if (instances == 0 || attrib.mDivisor == 0)
    118         {
    119             input += inputStride * start;
    120         }
    121 
    122         if (converter.identity && inputStride == elementSize)
    123         {
    124             memcpy(mapPtr, input, count * inputStride);
    125         }
    126         else
    127         {
    128             converter.convertArray(input, inputStride, count, mapPtr);
    129         }
    130 
    131         mVertexBuffer->Unlock();
    132 
    133         return true;
    134     }
    135     else
    136     {
    137         ERR("Vertex buffer not initialized.");
    138         return false;
    139     }
    140 }
    141 
    142 bool VertexBuffer9::storeRawData(const void* data, unsigned int size, unsigned int offset)
    143 {
    144     if (mVertexBuffer)
    145     {
    146         DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0;
    147 
    148         void *mapPtr = NULL;
    149         HRESULT result = mVertexBuffer->Lock(offset, size, &mapPtr, lockFlags);
    150 
    151         if (FAILED(result))
    152         {
    153             ERR("Lock failed with error 0x%08x", result);
    154             return false;
    155         }
    156 
    157         memcpy(mapPtr, data, size);
    158 
    159         mVertexBuffer->Unlock();
    160 
    161         return true;
    162     }
    163     else
    164     {
    165         ERR("Vertex buffer not initialized.");
    166         return false;
    167     }
    168 }
    169 
    170 unsigned int VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) const
    171 {
    172     return spaceRequired(attrib, count, instances);
    173 }
    174 
    175 bool VertexBuffer9::requiresConversion(const gl::VertexAttribute &attrib) const
    176 {
    177     return formatConverter(attrib).identity;
    178 }
    179 
    180 unsigned int VertexBuffer9::getVertexSize(const gl::VertexAttribute &attrib) const
    181 {
    182     return spaceRequired(attrib, 1, 0);
    183 }
    184 
    185 D3DDECLTYPE VertexBuffer9::getDeclType(const gl::VertexAttribute &attrib) const
    186 {
    187     return formatConverter(attrib).d3dDeclType;
    188 }
    189 
    190 unsigned int VertexBuffer9::getBufferSize() const
    191 {
    192     return mBufferSize;
    193 }
    194 
    195 bool VertexBuffer9::setBufferSize(unsigned int size)
    196 {
    197     if (size > mBufferSize)
    198     {
    199         return initialize(size, mDynamicUsage);
    200     }
    201     else
    202     {
    203         return true;
    204     }
    205 }
    206 
    207 bool VertexBuffer9::discard()
    208 {
    209     if (mVertexBuffer)
    210     {
    211         void *dummy;
    212         HRESULT result;
    213 
    214         result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
    215         if (FAILED(result))
    216         {
    217             ERR("Discard lock failed with error 0x%08x", result);
    218             return false;
    219         }
    220 
    221         result = mVertexBuffer->Unlock();
    222         if (FAILED(result))
    223         {
    224             ERR("Discard unlock failed with error 0x%08x", result);
    225             return false;
    226         }
    227 
    228         return true;
    229     }
    230     else
    231     {
    232         ERR("Vertex buffer not initialized.");
    233         return false;
    234     }
    235 }
    236 
    237 IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const
    238 {
    239     return mVertexBuffer;
    240 }
    241 
    242 // Mapping from OpenGL-ES vertex attrib type to D3D decl type:
    243 //
    244 // BYTE                 SHORT (Cast)
    245 // BYTE-norm            FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
    246 // UNSIGNED_BYTE        UBYTE4 (Identity) or SHORT (Cast)
    247 // UNSIGNED_BYTE-norm   UBYTE4N (Identity) or FLOAT (Normalize)
    248 // SHORT                SHORT (Identity)
    249 // SHORT-norm           SHORT-norm (Identity) or FLOAT (Normalize)
    250 // UNSIGNED_SHORT       FLOAT (Cast)
    251 // UNSIGNED_SHORT-norm  USHORT-norm (Identity) or FLOAT (Normalize)
    252 // FIXED (not in WebGL) FLOAT (FixedToFloat)
    253 // FLOAT                FLOAT (Identity)
    254 
    255 // GLToCType maps from GL type (as GLenum) to the C typedef.
    256 template <GLenum GLType> struct GLToCType { };
    257 
    258 template <> struct GLToCType<GL_BYTE>           { typedef GLbyte type;      };
    259 template <> struct GLToCType<GL_UNSIGNED_BYTE>  { typedef GLubyte type;     };
    260 template <> struct GLToCType<GL_SHORT>          { typedef GLshort type;     };
    261 template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type;    };
    262 template <> struct GLToCType<GL_FIXED>          { typedef GLuint type;      };
    263 template <> struct GLToCType<GL_FLOAT>          { typedef GLfloat type;     };
    264 
    265 // This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
    266 enum D3DVertexType
    267 {
    268     D3DVT_FLOAT,
    269     D3DVT_SHORT,
    270     D3DVT_SHORT_NORM,
    271     D3DVT_UBYTE,
    272     D3DVT_UBYTE_NORM,
    273     D3DVT_USHORT_NORM
    274 };
    275 
    276 // D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
    277 template <unsigned int D3DType> struct D3DToCType { };
    278 
    279 template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
    280 template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
    281 template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
    282 template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
    283 template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
    284 template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
    285 
    286 // Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
    287 template <unsigned int type, int size> struct WidenRule { };
    288 
    289 template <int size> struct WidenRule<D3DVT_FLOAT, size>          : NoWiden<size> { };
    290 template <int size> struct WidenRule<D3DVT_SHORT, size>          : WidenToEven<size> { };
    291 template <int size> struct WidenRule<D3DVT_SHORT_NORM, size>     : WidenToEven<size> { };
    292 template <int size> struct WidenRule<D3DVT_UBYTE, size>          : WidenToFour<size> { };
    293 template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size>     : WidenToFour<size> { };
    294 template <int size> struct WidenRule<D3DVT_USHORT_NORM, size>    : WidenToEven<size> { };
    295 
    296 // VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
    297 template <unsigned int d3dtype, int size> struct VertexTypeFlags { };
    298 
    299 template <unsigned int _capflag, unsigned int _declflag>
    300 struct VertexTypeFlagsHelper
    301 {
    302     enum { capflag = _capflag };
    303     enum { declflag = _declflag };
    304 };
    305 
    306 template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
    307 template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
    308 template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
    309 template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
    310 template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
    311 template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
    312 template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
    313 template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
    314 template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
    315 template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
    316 template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
    317 template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
    318 
    319 
    320 // VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
    321 template <GLenum GLtype, bool normalized> struct VertexTypeMapping { };
    322 
    323 template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
    324 struct VertexTypeMappingBase
    325 {
    326     enum { preferred = Preferred };
    327     enum { fallback = Fallback };
    328 };
    329 
    330 template <> struct VertexTypeMapping<GL_BYTE, false>                        : VertexTypeMappingBase<D3DVT_SHORT> { };                       // Cast
    331 template <> struct VertexTypeMapping<GL_BYTE, true>                         : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // Normalize
    332 template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false>               : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { };          // Identity, Cast
    333 template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true>                : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { };     // Identity, Normalize
    334 template <> struct VertexTypeMapping<GL_SHORT, false>                       : VertexTypeMappingBase<D3DVT_SHORT> { };                       // Identity
    335 template <> struct VertexTypeMapping<GL_SHORT, true>                        : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { };     // Cast, Normalize
    336 template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false>              : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // Cast
    337 template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true>               : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { };    // Cast, Normalize
    338 template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized>   : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // FixedToFloat
    339 template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized>   : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // Identity
    340 
    341 
    342 // Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
    343 // The conversion rules themselves are defined in vertexconversion.h.
    344 
    345 // Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
    346 template <GLenum fromType, bool normalized, unsigned int toType>
    347 struct ConversionRule : Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type> { };
    348 
    349 // All conversions from normalized types to float use the Normalize operator.
    350 template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : Normalize<typename GLToCType<fromType>::type> { };
    351 
    352 // Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules.
    353 template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT>  : FixedToFloat<GLint, 16> { };
    354 template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { };
    355 
    356 // A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
    357 // whether it is normalized or not.
    358 template <class T, bool normalized> struct DefaultVertexValuesStage2 { };
    359 
    360 template <class T> struct DefaultVertexValuesStage2<T, true>  : NormalizedDefaultValues<T> { };
    361 template <class T> struct DefaultVertexValuesStage2<T, false> : SimpleDefaultValues<T> { };
    362 
    363 // Work out the default value rule for a D3D type (expressed as the C type) and
    364 template <class T, bool normalized> struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized> { };
    365 template <bool normalized> struct DefaultVertexValues<float, normalized> : SimpleDefaultValues<float> { };
    366 
    367 // Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
    368 // The fallback conversion produces an output that all D3D9 devices must support.
    369 template <class T> struct UsePreferred { enum { type = T::preferred }; };
    370 template <class T> struct UseFallback { enum { type = T::fallback }; };
    371 
    372 // Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
    373 // it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
    374 // and the D3DDECLTYPE member needed for the vertex declaration in declflag.
    375 template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
    376 struct Converter
    377     : VertexDataConverter<typename GLToCType<fromType>::type,
    378                           WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
    379                           ConversionRule<fromType,
    380                                          normalized,
    381                                          PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
    382                           DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
    383 {
    384 private:
    385     enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
    386     enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
    387 
    388 public:
    389     enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
    390     enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
    391 };
    392 
    393 // Initialize a TranslationInfo
    394 #define TRANSLATION(type, norm, size, preferred)                                    \
    395     {                                                                               \
    396         Converter<type, norm, size, preferred>::identity,                           \
    397         Converter<type, norm, size, preferred>::finalSize,                          \
    398         Converter<type, norm, size, preferred>::convertArray,                       \
    399         static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag)  \
    400     }
    401 
    402 #define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size)    \
    403     {                                                       \
    404         Converter<type, norm, size, UsePreferred>::capflag, \
    405         TRANSLATION(type, norm, size, UsePreferred),        \
    406         TRANSLATION(type, norm, size, UseFallback)          \
    407     }
    408 
    409 #define TRANSLATIONS_FOR_TYPE(type)                                                                                                                                                                         \
    410     {                                                                                                                                                                                                       \
    411         { 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) }, \
    412         { 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) },     \
    413     }
    414 
    415 #define TRANSLATIONS_FOR_TYPE_NO_NORM(type)                                                                                                                                                                 \
    416     {                                                                                                                                                                                                       \
    417         { 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) }, \
    418         { 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) }, \
    419     }
    420 
    421 const VertexBuffer9::TranslationDescription VertexBuffer9::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
    422 {
    423     TRANSLATIONS_FOR_TYPE(GL_BYTE),
    424     TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
    425     TRANSLATIONS_FOR_TYPE(GL_SHORT),
    426     TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
    427     TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED),
    428     TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT)
    429 };
    430 
    431 void VertexBuffer9::initializeTranslations(DWORD declTypes)
    432 {
    433     for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
    434     {
    435         for (unsigned int j = 0; j < 2; j++)
    436         {
    437             for (unsigned int k = 0; k < 4; k++)
    438             {
    439                 if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0)
    440                 {
    441                     mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion;
    442                 }
    443                 else
    444                 {
    445                     mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion;
    446                 }
    447             }
    448         }
    449     }
    450 }
    451 
    452 unsigned int VertexBuffer9::typeIndex(GLenum type)
    453 {
    454     switch (type)
    455     {
    456       case GL_BYTE: return 0;
    457       case GL_UNSIGNED_BYTE: return 1;
    458       case GL_SHORT: return 2;
    459       case GL_UNSIGNED_SHORT: return 3;
    460       case GL_FIXED: return 4;
    461       case GL_FLOAT: return 5;
    462 
    463       default: UNREACHABLE(); return 5;
    464     }
    465 }
    466 
    467 const VertexBuffer9::FormatConverter &VertexBuffer9::formatConverter(const gl::VertexAttribute &attribute)
    468 {
    469     return mFormatConverters[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1];
    470 }
    471 
    472 unsigned int VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances)
    473 {
    474     unsigned int elementSize = formatConverter(attrib).outputElementSize;
    475 
    476     if (instances == 0 || attrib.mDivisor == 0)
    477     {
    478         return elementSize * count;
    479     }
    480     else
    481     {
    482         return elementSize * ((instances + attrib.mDivisor - 1) / attrib.mDivisor);
    483     }
    484 }
    485 
    486 }
    487