Commit 2e62a9a8 by Corentin Wallez

Simplify the flow of IndexDataManager::prepareIndexData

This will simplify the work on follow up CLs a lot BUG=angleproject:516 Change-Id: Ie8374ec28fce2e01e76c711a4d280e1ed004a21f Reviewed-on: https://chromium-review.googlesource.com/283380Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 3ebfcd62
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
// runs the Buffer translation process for index buffers. // runs the Buffer translation process for index buffers.
#include "libANGLE/renderer/d3d/IndexDataManager.h" #include "libANGLE/renderer/d3d/IndexDataManager.h"
#include "libANGLE/renderer/d3d/BufferD3D.h" #include "libANGLE/renderer/d3d/BufferD3D.h"
#include "libANGLE/renderer/d3d/IndexBuffer.h" #include "libANGLE/renderer/d3d/IndexBuffer.h"
#include "libANGLE/Buffer.h" #include "libANGLE/Buffer.h"
...@@ -16,7 +17,8 @@ ...@@ -16,7 +17,8 @@
namespace rx namespace rx
{ {
static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output) static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input,
GLsizei count, void *output)
{ {
if (sourceType == GL_UNSIGNED_BYTE) if (sourceType == GL_UNSIGNED_BYTE)
{ {
...@@ -55,6 +57,44 @@ static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void ...@@ -55,6 +57,44 @@ static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void
else UNREACHABLE(); else UNREACHABLE();
} }
static gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, const GLvoid *data,
unsigned int count, GLenum srcType, GLenum dstType,
unsigned int *offset)
{
const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
if (count > (std::numeric_limits<unsigned int>::max() >> dstTypeInfo.bytesShift))
{
return gl::Error(GL_OUT_OF_MEMORY,
"Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
count, dstTypeInfo.bytes);
}
unsigned int bufferSizeRequired = count << dstTypeInfo.bytesShift;
gl::Error error = buffer->reserveBufferSpace(bufferSizeRequired, dstType);
if (error.isError())
{
return error;
}
void *output = nullptr;
error = buffer->mapBuffer(bufferSizeRequired, &output, offset);
if (error.isError())
{
return error;
}
ConvertIndices(srcType, dstType, data, count, output);
error = buffer->unmapBuffer();
if (error.isError())
{
return error;
}
return gl::Error(GL_NO_ERROR);
}
IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass) IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass)
: mFactory(factory), : mFactory(factory),
mRendererClass(rendererClass), mRendererClass(rendererClass),
...@@ -69,175 +109,165 @@ IndexDataManager::~IndexDataManager() ...@@ -69,175 +109,165 @@ IndexDataManager::~IndexDataManager()
SafeDelete(mStreamingBufferInt); SafeDelete(mStreamingBufferInt);
} }
gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated, SourceIndexData *sourceData) // This function translates a GL-style indices into DX-style indices, with their description
// returned in translated.
// GL can specify vertex data in immediate mode (pointer to CPU array of indices), which is not
// possible in DX and requires streaming (Case 1). If the GL indices are specified with a buffer
// (Case 2), in a format supported by DX (subcase a) then all is good.
// When we have a buffer with an unsupported format (subcase b) then we need to do some translation:
// we will start by falling back to streaming, and after a while will start using a static translated
// copy of the index buffer.
gl::Error IndexDataManager::prepareIndexData(GLenum srcType, GLsizei count, gl::Buffer *glBuffer,
const GLvoid *indices, TranslatedIndexData *translated,
SourceIndexData *sourceData)
{ {
const gl::Type &typeInfo = gl::GetTypeInfo(type); // Avoid D3D11's primitive restart index value
// see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 &&
translated->indexRange.end == 0xFFFF &&
unsigned int offset = 0; srcType == GL_UNSIGNED_SHORT;
bool alignedOffset = false;
BufferD3D *storage = NULL;
if (buffer != NULL) const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround) ?
{ GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
storage = GetImplAs<BufferD3D>(buffer); const gl::Type &srcTypeInfo = gl::GetTypeInfo(srcType);
const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
// We'll trust that the compiler will optimize the % below: translated->indexType = dstType;
// the operands are unsigned and the divisor is a constant. if (sourceData)
switch (type)
{ {
case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break; sourceData->srcIndexType = srcType;
case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break; sourceData->srcCount = count;
case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
default: UNREACHABLE(); alignedOffset = false;
} }
ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize()); // Case 1: the indices are passed by pointer, which forces the streaming of index data
if (glBuffer == nullptr)
const uint8_t *bufferData = NULL;
gl::Error error = storage->getData(&bufferData);
if (error.isError())
{ {
return error; translated->storage = nullptr;
if (sourceData)
{
sourceData->srcIndices = indices;
} }
return streamIndexData(indices, count, srcType, dstType, translated);
indices = bufferData + offset;
} }
StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL; // Case 2: the indices are already in a buffer
IndexBufferInterface *indexBuffer = NULL; BufferD3D *buffer = GetImplAs<BufferD3D>(glBuffer);
bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
destinationIndexType == type;
unsigned int streamOffset = 0;
// Avoid D3D11's primitive restart index value
// see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 &&
translated->indexRange.end == 0xFFFF &&
type == GL_UNSIGNED_SHORT;
if (primitiveRestartWorkaround) unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
{ ASSERT(srcTypeInfo.bytes * static_cast<unsigned int>(count) + offset <= buffer->getSize());
destinationIndexType = GL_UNSIGNED_INT;
directStorage = false;
}
const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType); bool offsetAligned;
switch (srcType)
if (directStorage)
{ {
streamOffset = offset; case GL_UNSIGNED_BYTE: offsetAligned = (offset % sizeof(GLubyte) == 0); break;
case GL_UNSIGNED_SHORT: offsetAligned = (offset % sizeof(GLushort) == 0); break;
case GL_UNSIGNED_INT: offsetAligned = (offset % sizeof(GLuint) == 0); break;
default: UNREACHABLE(); offsetAligned = false;
} }
else if (staticBuffer &&
staticBuffer->getBufferSize() != 0 &&
alignedOffset &&
staticBuffer->getIndexType() == destinationIndexType)
{
indexBuffer = staticBuffer;
// Using bit-shift here is faster than using division. // TODO(cwallez) avoid doing this in all cases as it prevents optimizations
streamOffset = (offset >> typeInfo.bytesShift) << destTypeInfo.bytesShift; // of the sysmem buffer copy
} const uint8_t *bufferData = nullptr;
gl::Error error = buffer->getData(&bufferData);
if (!directStorage && !indexBuffer)
{
gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer);
if (error.isError()) if (error.isError())
{ {
return error; return error;
} }
ASSERT(bufferData != nullptr);
unsigned int convertCount = count; if (sourceData)
if (staticBuffer)
{ {
if (staticBuffer->getBufferSize() == 0 && alignedOffset) sourceData->srcIndices = bufferData + offset;
}
// Case 2a: the buffer can be used directly
if (offsetAligned && buffer->supportsDirectBinding() &&
dstType == srcType && !primitiveRestartWorkaround)
{ {
indexBuffer = staticBuffer; translated->storage = buffer;
// Using bit-shift here is faster than using division. translated->indexBuffer = nullptr;
convertCount = storage->getSize() >> typeInfo.bytesShift; translated->serial = buffer->getSerial();
translated->startIndex = (offset >> srcTypeInfo.bytesShift);
translated->startOffset = offset;
buffer->promoteStaticUsage(count << srcTypeInfo.bytesShift);
return gl::Error(GL_NO_ERROR);
} }
else else
{ {
storage->invalidateStaticData(); translated->storage = nullptr;
staticBuffer = NULL;
}
} }
ASSERT(indexBuffer); // Case 2b: use a static translated copy or fall back to streaming
StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();
// Using bit-shift here is faster than using division. bool staticBufferInitialized = staticBuffer && staticBuffer->getBufferSize() != 0;
if (convertCount > (std::numeric_limits<unsigned int>::max() >> destTypeInfo.bytesShift)) bool staticBufferUsable = staticBuffer &&
{ offsetAligned && staticBuffer->getIndexType() == dstType;
return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
convertCount, destTypeInfo.bytes);
}
unsigned int bufferSizeRequired = convertCount << destTypeInfo.bytesShift; if (staticBufferInitialized && !staticBufferUsable)
error = indexBuffer->reserveBufferSpace(bufferSizeRequired, destinationIndexType);
if (error.isError())
{ {
return error; buffer->invalidateStaticData();
staticBuffer = nullptr;
} }
void* output = NULL; if (staticBuffer == nullptr || !offsetAligned)
error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset); {
gl::Error error = streamIndexData(bufferData, count, srcType, dstType, translated);
if (error.isError()) if (error.isError())
{ {
return error; return error;
} }
}
const uint8_t *dataPointer = reinterpret_cast<const uint8_t*>(indices); else
if (staticBuffer)
{ {
error = storage->getData(&dataPointer); if (!staticBufferInitialized)
{
unsigned int convertCount = buffer->getSize() >> srcTypeInfo.bytesShift;
gl::Error error = StreamInIndexBuffer(staticBuffer, bufferData, convertCount,
srcType, dstType, nullptr);
if (error.isError()) if (error.isError())
{ {
return error; return error;
} }
} }
ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output); ASSERT(offsetAligned && staticBuffer->getIndexType() == dstType);
translated->indexBuffer = staticBuffer->getIndexBuffer();
translated->serial = staticBuffer->getSerial();
translated->startIndex = (offset >> srcTypeInfo.bytesShift);
translated->startOffset = (offset >> srcTypeInfo.bytesShift) << dstTypeInfo.bytesShift;
}
return gl::Error(GL_NO_ERROR);
}
gl::Error IndexDataManager::streamIndexData(const GLvoid *data, unsigned int count, GLenum srcType,
GLenum dstType, TranslatedIndexData *translated)
{
const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
error = indexBuffer->unmapBuffer(); IndexBufferInterface *indexBuffer = nullptr;
gl::Error error = getStreamingIndexBuffer(dstType, &indexBuffer);
if (error.isError()) if (error.isError())
{ {
return error; return error;
} }
ASSERT(indexBuffer != nullptr);
if (staticBuffer) unsigned int offset;
{ StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, &offset);
// Using bit-shift here is faster than using division.
streamOffset = (offset >> typeInfo.bytesShift) << destTypeInfo.bytesShift;
}
}
translated->storage = directStorage ? storage : NULL; translated->indexBuffer = indexBuffer->getIndexBuffer();
translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL; translated->serial = indexBuffer->getSerial();
translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial(); translated->startIndex = (offset >> dstTypeInfo.bytesShift);
// Using bit-shift here is faster than using division. translated->startOffset = offset;
translated->startIndex = (streamOffset >> destTypeInfo.bytesShift);
translated->startOffset = streamOffset;
translated->indexType = destinationIndexType;
if (sourceData)
{
// Update pretranslated source index data
sourceData->srcIndices = indices;
sourceData->srcIndexType = type;
sourceData->srcCount = count;
}
if (storage)
{
storage->promoteStaticUsage(count << typeInfo.bytesShift);
}
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer) gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
IndexBufferInterface **outBuffer)
{ {
ASSERT(outBuffer); ASSERT(outBuffer);
if (destinationIndexType == GL_UNSIGNED_INT) if (destinationIndexType == GL_UNSIGNED_INT)
...@@ -245,7 +275,8 @@ gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, ...@@ -245,7 +275,8 @@ gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
if (!mStreamingBufferInt) if (!mStreamingBufferInt)
{ {
mStreamingBufferInt = new StreamingIndexBufferInterface(mFactory); mStreamingBufferInt = new StreamingIndexBufferInterface(mFactory);
gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE,
GL_UNSIGNED_INT);
if (error.isError()) if (error.isError())
{ {
SafeDelete(mStreamingBufferInt); SafeDelete(mStreamingBufferInt);
...@@ -263,7 +294,8 @@ gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, ...@@ -263,7 +294,8 @@ gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
if (!mStreamingBufferShort) if (!mStreamingBufferShort)
{ {
mStreamingBufferShort = new StreamingIndexBufferInterface(mFactory); mStreamingBufferShort = new StreamingIndexBufferInterface(mFactory);
gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE,
GL_UNSIGNED_SHORT);
if (error.isError()) if (error.isError())
{ {
SafeDelete(mStreamingBufferShort); SafeDelete(mStreamingBufferShort);
......
...@@ -62,10 +62,15 @@ class IndexDataManager : angle::NonCopyable ...@@ -62,10 +62,15 @@ class IndexDataManager : angle::NonCopyable
explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass); explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass);
virtual ~IndexDataManager(); virtual ~IndexDataManager();
gl::Error prepareIndexData(GLenum type, GLsizei count, gl::Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated, SourceIndexData *sourceData); gl::Error prepareIndexData(GLenum srcType, GLsizei count, gl::Buffer *glBuffer,
const GLvoid *indices, TranslatedIndexData *translated,
SourceIndexData *sourceData);
private: private:
gl::Error getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer); gl::Error streamIndexData(const GLvoid *data, unsigned int count, GLenum srcType,
GLenum dstType, TranslatedIndexData *translated);
gl::Error getStreamingIndexBuffer(GLenum destinationIndexType,
IndexBufferInterface **outBuffer);
BufferFactoryD3D *const mFactory; BufferFactoryD3D *const mFactory;
RendererClass mRendererClass; RendererClass mRendererClass;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment