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