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