diff options
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp')
-rw-r--r-- | Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp | 383 |
1 files changed, 252 insertions, 131 deletions
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp index d573579..f79d606 100644 --- a/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp +++ b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp @@ -13,7 +13,7 @@ #include "libGLESv2/Buffer.h" #include "libGLESv2/mathutil.h" -#include "libGLESv2/geometry/backend.h" +#include "libGLESv2/main.h" namespace { @@ -23,239 +23,360 @@ namespace namespace gl { -IndexDataManager::IndexDataManager(Context *context, BufferBackEnd *backend) - : mContext(context), mBackend(backend), mIntIndicesSupported(backend->supportIntIndices()) +IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device) { - mCountingBuffer = NULL; - mCountingBufferSize = 0; + mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16); - mLineLoopBuffer = NULL; - - mStreamBufferShort = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); - - if (mIntIndicesSupported) + if (context->supports32bitIndices()) { - mStreamBufferInt = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32); } else { - mStreamBufferInt = NULL; + mStreamingBufferInt = NULL; } } IndexDataManager::~IndexDataManager() { - delete mStreamBufferShort; - delete mStreamBufferInt; - delete mCountingBuffer; - delete mLineLoopBuffer; + delete mStreamingBufferShort; + delete mStreamingBufferInt; } -namespace +void convertIndices(GLenum type, const void *input, GLsizei count, void *output) { + if (type == GL_UNSIGNED_BYTE) + { + const GLubyte *in = static_cast<const GLubyte*>(input); + GLushort *out = static_cast<GLushort*>(output); + + for (GLsizei i = 0; i < count; i++) + { + out[i] = in[i]; + } + } + else if (type == GL_UNSIGNED_INT) + { + memcpy(output, input, count * sizeof(GLuint)); + } + else if (type == GL_UNSIGNED_SHORT) + { + memcpy(output, input, count * sizeof(GLushort)); + } + else UNREACHABLE(); +} -template <class InputIndexType, class OutputIndexType> -void copyIndices(const InputIndexType *in, GLsizei count, OutputIndexType *out, GLuint *minIndex, GLuint *maxIndex) +template <class IndexType> +void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) { - InputIndexType first = *in; - GLuint minIndexSoFar = first; - GLuint maxIndexSoFar = first; + *minIndex = indices[0]; + *maxIndex = indices[0]; for (GLsizei i = 0; i < count; i++) { - if (minIndexSoFar > *in) minIndexSoFar = *in; - if (maxIndexSoFar < *in) maxIndexSoFar = *in; - - *out++ = *in++; + if (*minIndex > indices[i]) *minIndex = indices[i]; + if (*maxIndex < indices[i]) *maxIndex = indices[i]; } - - // It might be a line loop, so copy the loop index. - *out = first; - - *minIndex = minIndexSoFar; - *maxIndex = maxIndexSoFar; } +void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) +{ + if (type == GL_UNSIGNED_BYTE) + { + computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex); + } + else if (type == GL_UNSIGNED_INT) + { + computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex); + } + else if (type == GL_UNSIGNED_SHORT) + { + computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex); + } + else UNREACHABLE(); } -GLenum IndexDataManager::preRenderValidate(GLenum mode, GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated) +GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated) { - ASSERT(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT); - ASSERT(count > 0); + D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16; + intptr_t offset = reinterpret_cast<intptr_t>(indices); + bool alignedOffset = false; - if (arrayElementBuffer != NULL) + if (buffer != NULL) { - GLsizei offset = reinterpret_cast<GLsizei>(indices); + switch (type) + { + case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break; + case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break; + case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break; + default: UNREACHABLE(); alignedOffset = false; + } - if (typeSize(type) * count + offset > static_cast<std::size_t>(arrayElementBuffer->size())) + if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size())) { return GL_INVALID_OPERATION; } - indices = static_cast<const GLubyte*>(arrayElementBuffer->data()) + offset; + indices = static_cast<const GLubyte*>(buffer->data()) + offset; } - translated->count = count; - - std::size_t requiredSpace = spaceRequired(type, count); - - TranslatedIndexBuffer *streamIb = prepareIndexBuffer(type, requiredSpace); + StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort; - size_t offset; - void *output = streamIb->map(requiredSpace, &offset); + StaticIndexBuffer *staticBuffer = buffer ? buffer->getIndexBuffer() : NULL; + IndexBuffer *indexBuffer = streamingBuffer; + UINT streamOffset = 0; - translated->buffer = streamIb; - translated->offset = offset; - translated->indexSize = indexSize(type); - - if (type == GL_UNSIGNED_BYTE) + if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset) { - const GLubyte *in = static_cast<const GLubyte*>(indices); - GLushort *out = static_cast<GLushort*>(output); + indexBuffer = staticBuffer; + streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex); - copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex); + if (streamOffset == -1) + { + streamOffset = (offset / typeSize(type)) * indexSize(format); + computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); + staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset); + } } - else if (type == GL_UNSIGNED_INT) + else { - const GLuint *in = static_cast<const GLuint*>(indices); + int convertCount = count; - if (mIntIndicesSupported) + if (staticBuffer) { - GLuint *out = static_cast<GLuint*>(output); + if (staticBuffer->size() == 0 && alignedOffset) + { + indexBuffer = staticBuffer; + convertCount = buffer->size() / typeSize(type); + } + else + { + buffer->invalidateStaticData(); + staticBuffer = NULL; + } + } - copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex); + void *output = NULL; + + if (indexBuffer) + { + indexBuffer->reserveSpace(convertCount * indexSize(format), type); + output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset); } - else + + if (output == NULL) { - // When 32-bit indices are unsupported, fake them by truncating to 16-bit. + ERR("Failed to map index buffer."); + return GL_OUT_OF_MEMORY; + } - GLushort *out = static_cast<GLushort*>(output); + convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output); + indexBuffer->unmap(); - copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex); - } - } - else - { - const GLushort *in = static_cast<const GLushort*>(indices); - GLushort *out = static_cast<GLushort*>(output); + computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); - copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex); + if (staticBuffer) + { + streamOffset = (offset / typeSize(type)) * indexSize(format); + staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset); + } } - streamIb->unmap(); + translated->indexBuffer = indexBuffer->getBuffer(); + translated->startIndex = streamOffset / indexSize(format); return GL_NO_ERROR; } -std::size_t IndexDataManager::indexSize(GLenum type) const +std::size_t IndexDataManager::indexSize(D3DFORMAT format) const { - return (type == GL_UNSIGNED_INT && mIntIndicesSupported) ? sizeof(GLuint) : sizeof(GLushort); + return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short); } std::size_t IndexDataManager::typeSize(GLenum type) const { switch (type) { - case GL_UNSIGNED_INT: return sizeof(GLuint); + case GL_UNSIGNED_INT: return sizeof(GLuint); case GL_UNSIGNED_SHORT: return sizeof(GLushort); - default: UNREACHABLE(); - case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + default: UNREACHABLE(); return sizeof(GLushort); } } -std::size_t IndexDataManager::spaceRequired(GLenum type, GLsizei count) const +IndexBuffer::IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format) : mDevice(device), mBufferSize(size), mIndexBuffer(NULL) { - return (count + 1) * indexSize(type); // +1 because we always leave an extra for line loops + if (size > 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY); + HRESULT result = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, pool, &mIndexBuffer, NULL); + + if (FAILED(result)) + { + ERR("Out of memory allocating an index buffer of size %lu.", size); + } + } } -TranslatedIndexBuffer *IndexDataManager::prepareIndexBuffer(GLenum type, std::size_t requiredSpace) +IndexBuffer::~IndexBuffer() { - bool use32 = (type == GL_UNSIGNED_INT && mIntIndicesSupported); + if (mIndexBuffer) + { + mIndexBuffer->Release(); + } +} - TranslatedIndexBuffer *streamIb = use32 ? mStreamBufferInt : mStreamBufferShort; +IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const +{ + return mIndexBuffer; +} - if (requiredSpace > streamIb->size()) +void IndexBuffer::unmap() +{ + if (mIndexBuffer) { - std::size_t newSize = std::max(requiredSpace, 2 * streamIb->size()); + mIndexBuffer->Unlock(); + } +} - TranslatedIndexBuffer *newStreamBuffer = mBackend->createIndexBuffer(newSize, use32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT); +StreamingIndexBuffer::StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format) : IndexBuffer(device, initialSize, format) +{ + mWritePosition = 0; +} - delete streamIb; +StreamingIndexBuffer::~StreamingIndexBuffer() +{ +} - streamIb = newStreamBuffer; +void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset) +{ + void *mapPtr = NULL; - if (use32) - { - mStreamBufferInt = streamIb; - } - else + if (mIndexBuffer) + { + HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE); + + if (FAILED(result)) { - mStreamBufferShort = streamIb; + ERR(" Lock failed with error 0x%08x", result); + return NULL; } - } - streamIb->reserveSpace(requiredSpace); + *offset = mWritePosition; + mWritePosition += requiredSpace; + } - return streamIb; + return mapPtr; } -GLenum IndexDataManager::preRenderValidateUnindexed(GLenum mode, GLsizei count, TranslatedIndexData *indexInfo) +void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type) { - if (count >= 65535) return GL_OUT_OF_MEMORY; - - if (mode == GL_LINE_LOOP) + if (requiredSpace > mBufferSize) { - // For line loops, create a single-use buffer that runs 0 - count-1, 0. - delete mLineLoopBuffer; - mLineLoopBuffer = mBackend->createIndexBuffer((count+1) * sizeof(unsigned short), GL_UNSIGNED_SHORT); - - unsigned short *indices = static_cast<unsigned short *>(mLineLoopBuffer->map()); - - for (int i = 0; i < count; i++) + if (mIndexBuffer) { - indices[i] = i; + mIndexBuffer->Release(); + mIndexBuffer = NULL; } - indices[count] = 0; + mBufferSize = std::max(requiredSpace, 2 * mBufferSize); - mLineLoopBuffer->unmap(); + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize); + } - indexInfo->buffer = mLineLoopBuffer; - indexInfo->count = count + 1; - indexInfo->maxIndex = count - 1; + mWritePosition = 0; } - else if (mCountingBufferSize < count) + else if (mWritePosition + requiredSpace > mBufferSize) // Recycle { - mCountingBufferSize = std::max(static_cast<GLsizei>(ceilPow2(count)), mCountingBufferSize*2); + void *dummy; + mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + mIndexBuffer->Unlock(); - delete mCountingBuffer; - mCountingBuffer = mBackend->createIndexBuffer(count * sizeof(unsigned short), GL_UNSIGNED_SHORT); + mWritePosition = 0; + } +} - unsigned short *indices = static_cast<unsigned short *>(mCountingBuffer->map()); +StaticIndexBuffer::StaticIndexBuffer(IDirect3DDevice9 *device) : IndexBuffer(device, 0, D3DFMT_UNKNOWN) +{ + mCacheType = GL_NONE; +} - for (int i = 0; i < count; i++) +StaticIndexBuffer::~StaticIndexBuffer() +{ +} + +void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset) +{ + void *mapPtr = NULL; + + if (mIndexBuffer) + { + HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0); + + if (FAILED(result)) { - indices[i] = i; + ERR(" Lock failed with error 0x%08x", result); + return NULL; } - mCountingBuffer->unmap(); + *offset = 0; + } + + return mapPtr; +} + +void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type) +{ + if (!mIndexBuffer && mBufferSize == 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize); + } - indexInfo->buffer = mCountingBuffer; - indexInfo->count = count; - indexInfo->maxIndex = count - 1; + mBufferSize = requiredSpace; + mCacheType = type; } - else + else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type) { - indexInfo->buffer = mCountingBuffer; - indexInfo->count = count; - indexInfo->maxIndex = count - 1; + // Already allocated } + else UNREACHABLE(); // Static index buffers can't be resized +} - indexInfo->indexSize = sizeof(unsigned short); - indexInfo->minIndex = 0; - indexInfo->offset = 0; +bool StaticIndexBuffer::lookupType(GLenum type) +{ + return mCacheType == type; +} - return GL_NO_ERROR; +UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex) +{ + for (unsigned int range = 0; range < mCache.size(); range++) + { + if (mCache[range].offset == offset && mCache[range].count == count) + { + *minIndex = mCache[range].minIndex; + *maxIndex = mCache[range].maxIndex; + + return mCache[range].streamOffset; + } + } + + return -1; +} + +void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset) +{ + IndexRange indexRange = {offset, count, minIndex, maxIndex, streamOffset}; + mCache.push_back(indexRange); } } |