summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/renderer/d3d/IndexDataManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/renderer/d3d/IndexDataManager.cpp')
-rw-r--r--gfx/angle/checkout/src/libANGLE/renderer/d3d/IndexDataManager.cpp318
1 files changed, 318 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/IndexDataManager.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/IndexDataManager.cpp
new file mode 100644
index 0000000000..dd8f45342f
--- /dev/null
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/IndexDataManager.cpp
@@ -0,0 +1,318 @@
+//
+// Copyright 2002 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexDataManager.cpp: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#include "libANGLE/renderer/d3d/IndexDataManager.h"
+
+#include "common/utilities.h"
+#include "libANGLE/Buffer.h"
+#include "libANGLE/Context.h"
+#include "libANGLE/VertexArray.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/BufferD3D.h"
+#include "libANGLE/renderer/d3d/ContextD3D.h"
+#include "libANGLE/renderer/d3d/IndexBuffer.h"
+
+namespace rx
+{
+
+namespace
+{
+
+template <typename InputT, typename DestT>
+void ConvertIndexArray(const void *input,
+ gl::DrawElementsType sourceType,
+ void *output,
+ gl::DrawElementsType 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] == srcRestartIndex ? destRestartIndex : static_cast<DestT>(in[i]));
+ }
+ }
+ else
+ {
+ for (GLsizei i = 0; i < count; i++)
+ {
+ out[i] = static_cast<DestT>(in[i]);
+ }
+ }
+}
+
+void ConvertIndices(gl::DrawElementsType sourceType,
+ gl::DrawElementsType destinationType,
+ const void *input,
+ GLsizei count,
+ void *output,
+ bool usePrimitiveRestartFixedIndex)
+{
+ if (sourceType == destinationType)
+ {
+ const GLuint dstTypeSize = gl::GetDrawElementsTypeSize(destinationType);
+ memcpy(output, input, count * dstTypeSize);
+ return;
+ }
+
+ if (sourceType == gl::DrawElementsType::UnsignedByte)
+ {
+ ASSERT(destinationType == gl::DrawElementsType::UnsignedShort);
+ ConvertIndexArray<GLubyte, GLushort>(input, sourceType, output, destinationType, count,
+ usePrimitiveRestartFixedIndex);
+ }
+ else if (sourceType == gl::DrawElementsType::UnsignedShort)
+ {
+ ASSERT(destinationType == gl::DrawElementsType::UnsignedInt);
+ ConvertIndexArray<GLushort, GLuint>(input, sourceType, output, destinationType, count,
+ usePrimitiveRestartFixedIndex);
+ }
+ else
+ UNREACHABLE();
+}
+
+angle::Result StreamInIndexBuffer(const gl::Context *context,
+ IndexBufferInterface *buffer,
+ const void *data,
+ unsigned int count,
+ gl::DrawElementsType srcType,
+ gl::DrawElementsType dstType,
+ bool usePrimitiveRestartFixedIndex,
+ unsigned int *offset)
+{
+ const GLuint dstTypeBytesShift = gl::GetDrawElementsTypeShift(dstType);
+
+ bool check = (count > (std::numeric_limits<unsigned int>::max() >> dstTypeBytesShift));
+ ANGLE_CHECK(GetImplAs<ContextD3D>(context), !check,
+ "Reserving indices exceeds the maximum buffer size.", GL_OUT_OF_MEMORY);
+
+ unsigned int bufferSizeRequired = count << dstTypeBytesShift;
+ ANGLE_TRY(buffer->reserveBufferSpace(context, bufferSizeRequired, dstType));
+
+ void *output = nullptr;
+ ANGLE_TRY(buffer->mapBuffer(context, bufferSizeRequired, &output, offset));
+
+ ConvertIndices(srcType, dstType, data, count, output, usePrimitiveRestartFixedIndex);
+
+ ANGLE_TRY(buffer->unmapBuffer(context));
+ return angle::Result::Continue;
+}
+} // anonymous namespace
+
+// IndexDataManager implementation.
+IndexDataManager::IndexDataManager(BufferFactoryD3D *factory)
+ : mFactory(factory), mStreamingBufferShort(), mStreamingBufferInt()
+{}
+
+IndexDataManager::~IndexDataManager() {}
+
+void IndexDataManager::deinitialize()
+{
+ mStreamingBufferShort.reset();
+ mStreamingBufferInt.reset();
+}
+
+// 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.
+angle::Result IndexDataManager::prepareIndexData(const gl::Context *context,
+ gl::DrawElementsType srcType,
+ gl::DrawElementsType dstType,
+ GLsizei count,
+ gl::Buffer *glBuffer,
+ const void *indices,
+ TranslatedIndexData *translated)
+{
+ GLuint srcTypeBytes = gl::GetDrawElementsTypeSize(srcType);
+ GLuint srcTypeShift = gl::GetDrawElementsTypeShift(srcType);
+ GLuint dstTypeShift = gl::GetDrawElementsTypeShift(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;
+
+ // Context can be nullptr in perf tests.
+ bool primitiveRestartFixedIndexEnabled =
+ context ? context->getState().isPrimitiveRestartEnabled() : false;
+
+ // Case 1: the indices are passed by pointer, which forces the streaming of index data
+ if (glBuffer == nullptr)
+ {
+ translated->storage = nullptr;
+ return streamIndexData(context, indices, count, srcType, dstType,
+ primitiveRestartFixedIndexEnabled, translated);
+ }
+
+ // Case 2: the indices are already in a buffer
+ unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
+ ASSERT(srcTypeBytes * static_cast<unsigned int>(count) + offset <= buffer->getSize());
+
+ bool offsetAligned = IsOffsetAligned(srcType, offset);
+
+ // Case 2a: the buffer can be used directly
+ if (offsetAligned && buffer->supportsDirectBinding() && dstType == srcType)
+ {
+ translated->storage = buffer;
+ translated->indexBuffer = nullptr;
+ translated->serial = buffer->getSerial();
+ translated->startIndex = (offset >> srcTypeShift);
+ translated->startOffset = offset;
+ return angle::Result::Continue;
+ }
+
+ translated->storage = nullptr;
+
+ // Case 2b: use a static translated copy or fall back to streaming
+ StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();
+
+ bool staticBufferInitialized = staticBuffer && staticBuffer->getBufferSize() != 0;
+ bool staticBufferUsable =
+ staticBuffer && offsetAligned && staticBuffer->getIndexType() == dstType;
+
+ if (staticBufferInitialized && !staticBufferUsable)
+ {
+ buffer->invalidateStaticData(context);
+ staticBuffer = nullptr;
+ }
+
+ if (staticBuffer == nullptr || !offsetAligned)
+ {
+ const uint8_t *bufferData = nullptr;
+ ANGLE_TRY(buffer->getData(context, &bufferData));
+ ASSERT(bufferData != nullptr);
+
+ ANGLE_TRY(streamIndexData(context, bufferData + offset, count, srcType, dstType,
+ primitiveRestartFixedIndexEnabled, translated));
+ buffer->promoteStaticUsage(context, count << srcTypeShift);
+ }
+ else
+ {
+ if (!staticBufferInitialized)
+ {
+ const uint8_t *bufferData = nullptr;
+ ANGLE_TRY(buffer->getData(context, &bufferData));
+ ASSERT(bufferData != nullptr);
+
+ unsigned int convertCount =
+ static_cast<unsigned int>(buffer->getSize()) >> srcTypeShift;
+ ANGLE_TRY(StreamInIndexBuffer(context, staticBuffer, bufferData, convertCount, srcType,
+ dstType, primitiveRestartFixedIndexEnabled, nullptr));
+ }
+ ASSERT(offsetAligned && staticBuffer->getIndexType() == dstType);
+
+ translated->indexBuffer = staticBuffer->getIndexBuffer();
+ translated->serial = staticBuffer->getSerial();
+ translated->startIndex = (offset >> srcTypeShift);
+ translated->startOffset = (offset >> srcTypeShift) << dstTypeShift;
+ }
+
+ return angle::Result::Continue;
+}
+
+angle::Result IndexDataManager::streamIndexData(const gl::Context *context,
+ const void *data,
+ unsigned int count,
+ gl::DrawElementsType srcType,
+ gl::DrawElementsType dstType,
+ bool usePrimitiveRestartFixedIndex,
+ TranslatedIndexData *translated)
+{
+ const GLuint dstTypeShift = gl::GetDrawElementsTypeShift(dstType);
+
+ IndexBufferInterface *indexBuffer = nullptr;
+ ANGLE_TRY(getStreamingIndexBuffer(context, dstType, &indexBuffer));
+ ASSERT(indexBuffer != nullptr);
+
+ unsigned int offset;
+ ANGLE_TRY(StreamInIndexBuffer(context, indexBuffer, data, count, srcType, dstType,
+ usePrimitiveRestartFixedIndex, &offset));
+
+ translated->indexBuffer = indexBuffer->getIndexBuffer();
+ translated->serial = indexBuffer->getSerial();
+ translated->startIndex = (offset >> dstTypeShift);
+ translated->startOffset = offset;
+
+ return angle::Result::Continue;
+}
+
+angle::Result IndexDataManager::getStreamingIndexBuffer(const gl::Context *context,
+ gl::DrawElementsType destinationIndexType,
+ IndexBufferInterface **outBuffer)
+{
+ ASSERT(outBuffer);
+ ASSERT(destinationIndexType == gl::DrawElementsType::UnsignedShort ||
+ destinationIndexType == gl::DrawElementsType::UnsignedInt);
+
+ auto &streamingBuffer = (destinationIndexType == gl::DrawElementsType::UnsignedInt)
+ ? mStreamingBufferInt
+ : mStreamingBufferShort;
+
+ if (!streamingBuffer)
+ {
+ StreamingBuffer newBuffer(new StreamingIndexBufferInterface(mFactory));
+ ANGLE_TRY(newBuffer->reserveBufferSpace(context, INITIAL_INDEX_BUFFER_SIZE,
+ destinationIndexType));
+ streamingBuffer = std::move(newBuffer);
+ }
+
+ *outBuffer = streamingBuffer.get();
+ return angle::Result::Continue;
+}
+
+angle::Result GetIndexTranslationDestType(const gl::Context *context,
+ GLsizei indexCount,
+ gl::DrawElementsType indexType,
+ const void *indices,
+ bool usePrimitiveRestartWorkaround,
+ gl::DrawElementsType *destTypeOut)
+{
+ // Avoid D3D11's primitive restart index value
+ // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
+ if (usePrimitiveRestartWorkaround)
+ {
+ // Conservatively assume we need to translate the indices for draw indirect.
+ // This is a bit of a trick. We assume the count for an indirect draw is zero.
+ if (indexCount == 0)
+ {
+ *destTypeOut = gl::DrawElementsType::UnsignedInt;
+ return angle::Result::Continue;
+ }
+
+ gl::IndexRange indexRange;
+ ANGLE_TRY(context->getState().getVertexArray()->getIndexRange(
+ context, indexType, indexCount, indices, &indexRange));
+ if (indexRange.end == gl::GetPrimitiveRestartIndex(indexType))
+ {
+ *destTypeOut = gl::DrawElementsType::UnsignedInt;
+ return angle::Result::Continue;
+ }
+ }
+
+ *destTypeOut = (indexType == gl::DrawElementsType::UnsignedInt)
+ ? gl::DrawElementsType::UnsignedInt
+ : gl::DrawElementsType::UnsignedShort;
+ return angle::Result::Continue;
+}
+
+} // namespace rx