summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp')
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp373
1 files changed, 230 insertions, 143 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp
index 7dad269435..f1ba3d3db0 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp
@@ -8,6 +8,8 @@
// runs the Buffer translation process for index buffers.
#include "libANGLE/renderer/d3d/IndexDataManager.h"
+
+#include "common/utilities.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
#include "libANGLE/renderer/d3d/IndexBuffer.h"
#include "libANGLE/Buffer.h"
@@ -16,45 +18,111 @@
namespace rx
{
-static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
+namespace
{
- if (sourceType == GL_UNSIGNED_BYTE)
- {
- ASSERT(destinationType == GL_UNSIGNED_SHORT);
- const GLubyte *in = static_cast<const GLubyte*>(input);
- GLushort *out = static_cast<GLushort*>(output);
+template <typename InputT, typename DestT>
+void ConvertIndexArray(const void *input,
+ GLenum sourceType,
+ void *output,
+ GLenum destinationType,
+ GLsizei count,
+ bool usePrimitiveRestartFixedIndex)
+{
+ const InputT *in = static_cast<const InputT *>(input);
+ DestT *out = static_cast<DestT *>(output);
+
+ if (usePrimitiveRestartFixedIndex)
+ {
+ InputT srcRestartIndex = static_cast<InputT>(gl::GetPrimitiveRestartIndex(sourceType));
+ DestT destRestartIndex = static_cast<DestT>(gl::GetPrimitiveRestartIndex(destinationType));
for (GLsizei i = 0; i < count; i++)
{
- out[i] = in[i];
+ out[i] = (in[i] == srcRestartIndex ? destRestartIndex : static_cast<DestT>(in[i]));
}
}
- else if (sourceType == GL_UNSIGNED_INT)
- {
- ASSERT(destinationType == GL_UNSIGNED_INT);
- memcpy(output, input, count * sizeof(GLuint));
- }
- else if (sourceType == GL_UNSIGNED_SHORT)
+ else
{
- if (destinationType == GL_UNSIGNED_SHORT)
+ for (GLsizei i = 0; i < count; i++)
{
- memcpy(output, input, count * sizeof(GLushort));
+ out[i] = static_cast<DestT>(in[i]);
}
- else if (destinationType == GL_UNSIGNED_INT)
- {
- const GLushort *in = static_cast<const GLushort*>(input);
- GLuint *out = static_cast<GLuint*>(output);
+ }
+}
- for (GLsizei i = 0; i < count; i++)
- {
- out[i] = in[i];
- }
- }
- else UNREACHABLE();
+void ConvertIndices(GLenum sourceType,
+ GLenum destinationType,
+ const void *input,
+ GLsizei count,
+ void *output,
+ bool usePrimitiveRestartFixedIndex)
+{
+ if (sourceType == destinationType)
+ {
+ const gl::Type &typeInfo = gl::GetTypeInfo(destinationType);
+ memcpy(output, input, count * typeInfo.bytes);
+ return;
+ }
+
+ if (sourceType == GL_UNSIGNED_BYTE)
+ {
+ ASSERT(destinationType == GL_UNSIGNED_SHORT);
+ ConvertIndexArray<GLubyte, GLushort>(input, sourceType, output, destinationType, count,
+ usePrimitiveRestartFixedIndex);
+ }
+ else if (sourceType == GL_UNSIGNED_SHORT)
+ {
+ ASSERT(destinationType == GL_UNSIGNED_INT);
+ ConvertIndexArray<GLushort, GLuint>(input, sourceType, output, destinationType, count,
+ usePrimitiveRestartFixedIndex);
}
else UNREACHABLE();
}
+gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer,
+ const GLvoid *data,
+ unsigned int count,
+ GLenum srcType,
+ GLenum dstType,
+ bool usePrimitiveRestartFixedIndex,
+ 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, usePrimitiveRestartFixedIndex);
+
+ error = buffer->unmapBuffer();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+} // anonymous namespace
+
IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass)
: mFactory(factory),
mRendererClass(rendererClass),
@@ -69,163 +137,180 @@ IndexDataManager::~IndexDataManager()
SafeDelete(mStreamingBufferInt);
}
-gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
+// 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,
+ bool primitiveRestartFixedIndexEnabled)
{
- const gl::Type &typeInfo = gl::GetTypeInfo(type);
-
- GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
-
- unsigned int offset = 0;
- bool alignedOffset = false;
-
- BufferD3D *storage = NULL;
-
- if (buffer != NULL)
+ // Avoid D3D11's primitive restart index value
+ // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
+ bool hasPrimitiveRestartIndex =
+ translated->indexRange.vertexIndexCount < static_cast<size_t>(count) ||
+ translated->indexRange.end == gl::GetPrimitiveRestartIndex(srcType);
+ bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 &&
+ !primitiveRestartFixedIndexEnabled &&
+ hasPrimitiveRestartIndex && srcType == GL_UNSIGNED_SHORT;
+
+ // We should never have to deal with MAX_UINT indices, since we restrict it via
+ // MAX_ELEMENT_INDEX.
+ ASSERT(!(mRendererClass == RENDERER_D3D11 && !primitiveRestartFixedIndexEnabled &&
+ hasPrimitiveRestartIndex && srcType == GL_UNSIGNED_INT));
+
+ const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround) ?
+ GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
+
+ const gl::Type &srcTypeInfo = gl::GetTypeInfo(srcType);
+ const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
+
+ BufferD3D *buffer = glBuffer ? GetImplAs<BufferD3D>(glBuffer) : nullptr;
+
+ translated->indexType = dstType;
+ translated->srcIndexData.srcBuffer = buffer;
+ translated->srcIndexData.srcIndices = indices;
+ translated->srcIndexData.srcIndexType = srcType;
+ translated->srcIndexData.srcCount = count;
+
+ // Case 1: the indices are passed by pointer, which forces the streaming of index data
+ if (glBuffer == nullptr)
{
- offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
-
- storage = GetImplAs<BufferD3D>(buffer);
-
- // We'll trust that the compiler will optimize the % below:
- // the operands are unsigned and the divisor is a constant.
- 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;
- }
-
- ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize());
-
- const uint8_t *bufferData = NULL;
- gl::Error error = storage->getData(&bufferData);
- if (error.isError())
- {
- return error;
- }
-
- indices = bufferData + offset;
+ translated->storage = nullptr;
+ return streamIndexData(indices, count, srcType, dstType, primitiveRestartFixedIndexEnabled,
+ translated);
}
- StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
- IndexBufferInterface *indexBuffer = NULL;
- bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
- destinationIndexType == type;
- unsigned int streamOffset = 0;
+ // Case 2: the indices are already in a buffer
+ unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
+ ASSERT(srcTypeInfo.bytes * static_cast<unsigned int>(count) + offset <= buffer->getSize());
- if (directStorage)
+ bool offsetAligned;
+ switch (srcType)
{
- 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 && staticBuffer->getIndexType() == type && alignedOffset)
- {
- indexBuffer = staticBuffer;
- // Using bit-shift here is faster than using division.
- streamOffset = (offset >> typeInfo.bytesShift) << gl::GetTypeInfo(destinationIndexType).bytesShift;
- }
-
- // Avoid D3D11's primitive restart index value
- // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
- if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRendererClass == RENDERER_D3D11)
+ // Case 2a: the buffer can be used directly
+ if (offsetAligned && buffer->supportsDirectBinding() &&
+ dstType == srcType && !primitiveRestartWorkaround)
{
- destinationIndexType = GL_UNSIGNED_INT;
- directStorage = false;
- indexBuffer = NULL;
+ translated->storage = buffer;
+ translated->indexBuffer = nullptr;
+ translated->serial = buffer->getSerial();
+ translated->startIndex = (offset >> srcTypeInfo.bytesShift);
+ translated->startOffset = offset;
+ buffer->promoteStaticUsage(count << srcTypeInfo.bytesShift);
+ return gl::Error(GL_NO_ERROR);
}
-
- const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
-
- if (!directStorage && !indexBuffer)
+ else
{
- gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer);
- if (error.isError())
- {
- return error;
- }
-
- unsigned int convertCount = count;
+ translated->storage = nullptr;
+ }
- if (staticBuffer)
- {
- if (staticBuffer->getBufferSize() == 0 && alignedOffset)
- {
- indexBuffer = staticBuffer;
- // Using bit-shift here is faster than using division.
- convertCount = storage->getSize() >> typeInfo.bytesShift;
- }
- else
- {
- storage->invalidateStaticData();
- staticBuffer = NULL;
- }
- }
+ // Case 2b: use a static translated copy or fall back to streaming
+ StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();
- ASSERT(indexBuffer);
+ bool staticBufferInitialized = staticBuffer && staticBuffer->getBufferSize() != 0;
+ bool staticBufferUsable = staticBuffer &&
+ offsetAligned && staticBuffer->getIndexType() == dstType;
- // Using bit-shift here is faster than using division.
- if (convertCount > (std::numeric_limits<unsigned int>::max() >> destTypeInfo.bytesShift))
- {
- return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
- convertCount, destTypeInfo.bytes);
- }
+ if (staticBufferInitialized && !staticBufferUsable)
+ {
+ buffer->invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
+ staticBuffer = nullptr;
+ }
- unsigned int bufferSizeRequired = convertCount << destTypeInfo.bytesShift;
- error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
+ if (staticBuffer == nullptr || !offsetAligned)
+ {
+ const uint8_t *bufferData = nullptr;
+ gl::Error error = buffer->getData(&bufferData);
if (error.isError())
{
return error;
}
+ ASSERT(bufferData != nullptr);
- void* output = NULL;
- error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset);
+ error = streamIndexData(bufferData + offset, count, srcType, dstType,
+ primitiveRestartFixedIndexEnabled, translated);
if (error.isError())
{
return error;
}
-
- const uint8_t *dataPointer = reinterpret_cast<const uint8_t*>(indices);
- if (staticBuffer)
+ }
+ else
+ {
+ if (!staticBufferInitialized)
{
- error = storage->getData(&dataPointer);
+ const uint8_t *bufferData = nullptr;
+ gl::Error error = buffer->getData(&bufferData);
if (error.isError())
{
return error;
}
- }
- ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output);
+ ASSERT(bufferData != nullptr);
- error = indexBuffer->unmapBuffer();
- if (error.isError())
- {
- return error;
+ unsigned int convertCount =
+ static_cast<unsigned int>(buffer->getSize()) >> srcTypeInfo.bytesShift;
+ error = StreamInIndexBuffer(staticBuffer, bufferData, convertCount, srcType, dstType,
+ primitiveRestartFixedIndexEnabled, nullptr);
+ if (error.isError())
+ {
+ return error;
+ }
}
+ ASSERT(offsetAligned && staticBuffer->getIndexType() == dstType);
- if (staticBuffer)
- {
- // Using bit-shift here is faster than using division.
- streamOffset = (offset >> typeInfo.bytesShift) << destTypeInfo.bytesShift;
- }
+ translated->indexBuffer = staticBuffer->getIndexBuffer();
+ translated->serial = staticBuffer->getSerial();
+ translated->startIndex = (offset >> srcTypeInfo.bytesShift);
+ translated->startOffset = (offset >> srcTypeInfo.bytesShift) << dstTypeInfo.bytesShift;
}
- translated->storage = directStorage ? storage : NULL;
- translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
- translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
- // Using bit-shift here is faster than using division.
- translated->startIndex = (streamOffset >> destTypeInfo.bytesShift);
- translated->startOffset = streamOffset;
- translated->indexType = destinationIndexType;
+ return gl::Error(GL_NO_ERROR);
+}
- if (storage)
+gl::Error IndexDataManager::streamIndexData(const GLvoid *data,
+ unsigned int count,
+ GLenum srcType,
+ GLenum dstType,
+ bool usePrimitiveRestartFixedIndex,
+ TranslatedIndexData *translated)
+{
+ const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
+
+ IndexBufferInterface *indexBuffer = nullptr;
+ gl::Error error = getStreamingIndexBuffer(dstType, &indexBuffer);
+ if (error.isError())
{
- storage->promoteStaticUsage(count << typeInfo.bytesShift);
+ return error;
}
+ ASSERT(indexBuffer != nullptr);
+
+ unsigned int offset;
+ StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, usePrimitiveRestartFixedIndex,
+ &offset);
+
+ translated->indexBuffer = indexBuffer->getIndexBuffer();
+ translated->serial = indexBuffer->getSerial();
+ translated->startIndex = (offset >> dstTypeInfo.bytesShift);
+ translated->startOffset = offset;
return gl::Error(GL_NO_ERROR);
}
-gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer)
+gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
+ IndexBufferInterface **outBuffer)
{
ASSERT(outBuffer);
if (destinationIndexType == GL_UNSIGNED_INT)
@@ -233,7 +318,8 @@ gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
if (!mStreamingBufferInt)
{
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())
{
SafeDelete(mStreamingBufferInt);
@@ -251,7 +337,8 @@ gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
if (!mStreamingBufferShort)
{
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())
{
SafeDelete(mStreamingBufferShort);