Vulkan: Implement conversion to uint16 for drawElements with ubytes
Bug: angleproject:2646
Bug: angleproject:2659
Change-Id: If3c7a2b77d6acd18c8ca2522a427a43e10ed6db2
Reviewed-on: https://chromium-review.googlesource.com/1099420
Commit-Queue: Luc Ferron <lucferron@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
index 0b37d30..604e8b4 100644
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
@@ -37,6 +37,7 @@
mCurrentElementArrayBufferResource(nullptr),
mDynamicVertexData(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, kDynamicVertexDataSize),
mDynamicIndexData(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, kDynamicIndexDataSize),
+ mTranslatedByteIndexData(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, kDynamicIndexDataSize),
mLineLoopHelper(renderer),
mDirtyLineLoopTranslation(true),
mVertexBuffersDirty(false),
@@ -52,6 +53,7 @@
mDynamicVertexData.init(1, renderer);
mDynamicIndexData.init(1, renderer);
+ mTranslatedByteIndexData.init(1, renderer);
}
VertexArrayVk::~VertexArrayVk()
@@ -63,6 +65,7 @@
VkDevice device = vk::GetImpl(context)->getRenderer()->getDevice();
mDynamicVertexData.destroy(device);
mDynamicIndexData.destroy(device);
+ mTranslatedByteIndexData.destroy(device);
mLineLoopHelper.destroy(device);
}
@@ -495,11 +498,11 @@
{
ANGLE_TRY(onDraw(context, renderer, drawCallParams, commandBuffer, newCommandBuffer));
bool isLineLoop = drawCallParams.mode() == gl::PrimitiveMode::LineLoop;
- uintptr_t offset = mState.getElementArrayBuffer().get() && !isLineLoop
- ? reinterpret_cast<uintptr_t>(drawCallParams.indices())
- : 0;
+ gl::Buffer *glBuffer = mState.getElementArrayBuffer().get();
+ uintptr_t offset =
+ glBuffer && !isLineLoop ? reinterpret_cast<uintptr_t>(drawCallParams.indices()) : 0;
- if (!mState.getElementArrayBuffer().get() && !isLineLoop)
+ if (!glBuffer && !isLineLoop)
{
ANGLE_TRY(drawCallParams.ensureIndexRangeResolved(context));
ANGLE_TRY(streamIndexData(renderer, drawCallParams));
@@ -512,15 +515,52 @@
if (drawCallParams.type() == GL_UNSIGNED_BYTE &&
drawCallParams.mode() != gl::PrimitiveMode::LineLoop)
{
- // TODO(fjhenigman): Index format translation for non line-loop calls.
- UNIMPLEMENTED();
- return gl::InternalError()
- << "Unsigned byte translation is not implemented for indices in a buffer object";
+ // Unsigned bytes don't have direct support in Vulkan so we have to expand the
+ // memory to a GLushort.
+ BufferVk *bufferVk = vk::GetImpl(glBuffer);
+ void *srcDataMapping = nullptr;
+ ASSERT(!glBuffer->isMapped());
+ ANGLE_TRY(bufferVk->map(context, 0, &srcDataMapping));
+ uint8_t *srcData = reinterpret_cast<uint8_t *>(srcDataMapping);
+ intptr_t offsetIntoSrcData = reinterpret_cast<intptr_t>(drawCallParams.indices());
+ srcData += offsetIntoSrcData;
+
+ // Allocate a new buffer that's double the size of the buffer provided by the user to
+ // go from unsigned byte to unsigned short.
+ uint8_t *allocatedData = nullptr;
+ bool newBufferAllocated = false;
+ uint32_t expandedDataOffset = 0;
+ mTranslatedByteIndexData.allocate(
+ renderer, static_cast<size_t>(bufferVk->getSize()) * 2, &allocatedData,
+ &mCurrentElementArrayBufferHandle, &expandedDataOffset, &newBufferAllocated);
+ mCurrentElementArrayBufferOffset = static_cast<VkDeviceSize>(expandedDataOffset);
+
+ // Expand the source into the destination
+ ASSERT(!context->getGLState().isPrimitiveRestartEnabled());
+ uint16_t *expandedDst = reinterpret_cast<uint16_t *>(allocatedData);
+ for (GLsizei index = 0; index < bufferVk->getSize() - offsetIntoSrcData; index++)
+ {
+ expandedDst[index] = static_cast<GLushort>(srcData[index]);
+ }
+
+ // Make sure our writes are available.
+ mTranslatedByteIndexData.flush(renderer->getDevice());
+ GLboolean result = false;
+ ANGLE_TRY(bufferVk->unmap(context, &result));
+
+ // We do not add the offset from the drawCallParams here because we've already copied
+ // the source starting at the offset requested.
+ commandBuffer->bindIndexBuffer(mCurrentElementArrayBufferHandle,
+ mCurrentElementArrayBufferOffset,
+ gl_vk::GetIndexType(drawCallParams.type()));
+ }
+ else
+ {
+ commandBuffer->bindIndexBuffer(mCurrentElementArrayBufferHandle,
+ mCurrentElementArrayBufferOffset + offset,
+ gl_vk::GetIndexType(drawCallParams.type()));
}
- commandBuffer->bindIndexBuffer(mCurrentElementArrayBufferHandle,
- mCurrentElementArrayBufferOffset + offset,
- gl_vk::GetIndexType(drawCallParams.type()));
mLastIndexBufferOffset = offset;
const gl::State &glState = context->getGLState();