2
// Copyright (c) 2002-2012 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.
7
// IndexDataManager.cpp: Defines the IndexDataManager, a class that
8
// runs the Buffer translation process for index buffers.
10
#include "libGLESv2/IndexDataManager.h"
12
#include "common/debug.h"
14
#include "libGLESv2/Buffer.h"
15
#include "libGLESv2/mathutil.h"
16
#include "libGLESv2/main.h"
20
unsigned int IndexBuffer::mCurrentSerial = 1;
22
IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device)
24
mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
26
if (context->supports32bitIndices())
28
mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
30
if (!mStreamingBufferInt)
32
// Don't leave it in a half-initialized state
33
delete mStreamingBufferShort;
34
mStreamingBufferShort = NULL;
39
mStreamingBufferInt = NULL;
42
if (!mStreamingBufferShort)
44
ERR("Failed to allocate the streaming index buffer(s).");
47
mCountingBuffer = NULL;
50
IndexDataManager::~IndexDataManager()
52
delete mStreamingBufferShort;
53
delete mStreamingBufferInt;
54
delete mCountingBuffer;
57
void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
59
if (type == GL_UNSIGNED_BYTE)
61
const GLubyte *in = static_cast<const GLubyte*>(input);
62
GLushort *out = static_cast<GLushort*>(output);
64
for (GLsizei i = 0; i < count; i++)
69
else if (type == GL_UNSIGNED_INT)
71
memcpy(output, input, count * sizeof(GLuint));
73
else if (type == GL_UNSIGNED_SHORT)
75
memcpy(output, input, count * sizeof(GLushort));
80
template <class IndexType>
81
void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
83
*minIndex = indices[0];
84
*maxIndex = indices[0];
86
for (GLsizei i = 0; i < count; i++)
88
if (*minIndex > indices[i]) *minIndex = indices[i];
89
if (*maxIndex < indices[i]) *maxIndex = indices[i];
93
void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
95
if (type == GL_UNSIGNED_BYTE)
97
computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
99
else if (type == GL_UNSIGNED_INT)
101
computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
103
else if (type == GL_UNSIGNED_SHORT)
105
computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
110
GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
112
if (!mStreamingBufferShort)
114
return GL_OUT_OF_MEMORY;
117
D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
118
intptr_t offset = reinterpret_cast<intptr_t>(indices);
119
bool alignedOffset = false;
125
case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
126
case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
127
case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
128
default: UNREACHABLE(); alignedOffset = false;
131
if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
133
return GL_INVALID_OPERATION;
136
indices = static_cast<const GLubyte*>(buffer->data()) + offset;
139
StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
141
StaticIndexBuffer *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
142
IndexBuffer *indexBuffer = streamingBuffer;
143
UINT streamOffset = 0;
145
if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset)
147
indexBuffer = staticBuffer;
148
streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
150
if (streamOffset == -1)
152
streamOffset = (offset / typeSize(type)) * indexSize(format);
153
computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
154
staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
159
int convertCount = count;
163
if (staticBuffer->size() == 0 && alignedOffset)
165
indexBuffer = staticBuffer;
166
convertCount = buffer->size() / typeSize(type);
170
buffer->invalidateStaticData();
179
indexBuffer->reserveSpace(convertCount * indexSize(format), type);
180
output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset);
185
ERR("Failed to map index buffer.");
186
return GL_OUT_OF_MEMORY;
189
convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
190
indexBuffer->unmap();
192
computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
196
streamOffset = (offset / typeSize(type)) * indexSize(format);
197
staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
201
translated->indexBuffer = indexBuffer->getBuffer();
202
translated->serial = indexBuffer->getSerial();
203
translated->startIndex = streamOffset / indexSize(format);
207
buffer->promoteStaticUsage(count * typeSize(type));
213
std::size_t IndexDataManager::indexSize(D3DFORMAT format) const
215
return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short);
218
std::size_t IndexDataManager::typeSize(GLenum type) const
222
case GL_UNSIGNED_INT: return sizeof(GLuint);
223
case GL_UNSIGNED_SHORT: return sizeof(GLushort);
224
case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
225
default: UNREACHABLE(); return sizeof(GLushort);
229
StaticIndexBuffer *IndexDataManager::getCountingIndices(GLsizei count)
231
if (count <= 65536) // 16-bit indices
233
const unsigned int spaceNeeded = count * sizeof(unsigned short);
235
if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded)
237
delete mCountingBuffer;
238
mCountingBuffer = new StaticIndexBuffer(mDevice);
239
mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT);
242
unsigned short *data = static_cast<unsigned short*>(mCountingBuffer->map(spaceNeeded, &offset));
246
for(int i = 0; i < count; i++)
251
mCountingBuffer->unmap();
255
else if (mStreamingBufferInt) // 32-bit indices supported
257
const unsigned int spaceNeeded = count * sizeof(unsigned int);
259
if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded)
261
delete mCountingBuffer;
262
mCountingBuffer = new StaticIndexBuffer(mDevice);
263
mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_INT);
266
unsigned int *data = static_cast<unsigned int*>(mCountingBuffer->map(spaceNeeded, &offset));
270
for(int i = 0; i < count; i++)
275
mCountingBuffer->unmap();
281
return mCountingBuffer;
284
IndexBuffer::IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format) : mDevice(device), mBufferSize(size), mIndexBuffer(NULL)
288
D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
289
HRESULT result = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, pool, &mIndexBuffer, NULL);
290
mSerial = issueSerial();
294
ERR("Out of memory allocating an index buffer of size %lu.", size);
299
IndexBuffer::~IndexBuffer()
303
mIndexBuffer->Release();
307
IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const
312
unsigned int IndexBuffer::getSerial() const
317
unsigned int IndexBuffer::issueSerial()
319
return mCurrentSerial++;
322
void IndexBuffer::unmap()
326
mIndexBuffer->Unlock();
330
StreamingIndexBuffer::StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format) : IndexBuffer(device, initialSize, format)
335
StreamingIndexBuffer::~StreamingIndexBuffer()
339
void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset)
345
HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
349
ERR(" Lock failed with error 0x%08x", result);
353
*offset = mWritePosition;
354
mWritePosition += requiredSpace;
360
void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
362
if (requiredSpace > mBufferSize)
366
mIndexBuffer->Release();
370
mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
372
D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
373
HRESULT result = mDevice->CreateIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
374
mSerial = issueSerial();
378
ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
383
else if (mWritePosition + requiredSpace > mBufferSize) // Recycle
386
mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
387
mIndexBuffer->Unlock();
393
StaticIndexBuffer::StaticIndexBuffer(IDirect3DDevice9 *device) : IndexBuffer(device, 0, D3DFMT_UNKNOWN)
395
mCacheType = GL_NONE;
398
StaticIndexBuffer::~StaticIndexBuffer()
402
void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset)
408
HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0);
412
ERR(" Lock failed with error 0x%08x", result);
422
void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
424
if (!mIndexBuffer && mBufferSize == 0)
426
D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY);
427
HRESULT result = mDevice->CreateIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
428
mSerial = issueSerial();
432
ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
435
mBufferSize = requiredSpace;
438
else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type)
442
else UNREACHABLE(); // Static index buffers can't be resized
445
bool StaticIndexBuffer::lookupType(GLenum type)
447
return mCacheType == type;
450
UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex)
452
IndexRange range = {offset, count};
454
std::map<IndexRange, IndexResult>::iterator res = mCache.find(range);
456
if (res == mCache.end())
461
*minIndex = res->second.minIndex;
462
*maxIndex = res->second.maxIndex;
463
return res->second.streamOffset;
466
void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset)
468
IndexRange indexRange = {offset, count};
469
IndexResult indexResult = {minIndex, maxIndex, streamOffset};
470
mCache[indexRange] = indexResult;