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