Vulkan: Implement very basic DrawElements.
This implements getIndexRange for index validation, without any
caching. Vulkan does support a version of robust access, but it would
require the robust context creation attribute. Also, it differs slight
from the OpenGL spec.
Also note that this implementation does not create the index buffer
with the correct usage bits, but seems to work and doesn't produce an
error in the validation layers. We should probably update them.
This CL also doesn't impement index support for immediate data,
offsets, or the unsigned short index type.
BUG=angleproject:2167
Change-Id: I580930f85e23034b483f3ece62eb1faf8024d624
Reviewed-on: https://chromium-review.googlesource.com/681874
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Frank Henigman <fjhenigman@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/BufferVk.cpp b/src/libANGLE/renderer/vulkan/BufferVk.cpp
index 329335b..32bda7a 100644
--- a/src/libANGLE/renderer/vulkan/BufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/BufferVk.cpp
@@ -10,6 +10,7 @@
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "common/debug.h"
+#include "common/utilities.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
@@ -170,8 +171,19 @@
bool primitiveRestartEnabled,
gl::IndexRange *outRange)
{
- UNIMPLEMENTED();
- return gl::InternalError();
+ VkDevice device = GetImplAs<ContextVk>(context)->getDevice();
+
+ // TODO(jmadill): Consider keeping a shadow system memory copy in some cases.
+ ASSERT(mBuffer.valid());
+
+ const gl::Type &typeInfo = gl::GetTypeInfo(type);
+
+ uint8_t *mapPointer = nullptr;
+ ANGLE_TRY(mBuffer.getMemory().map(device, offset, typeInfo.bytes * count, 0, &mapPointer));
+
+ *outRange = gl::ComputeIndexRange(type, mapPointer, count, primitiveRestartEnabled);
+
+ return gl::NoError();
}
vk::Error BufferVk::setDataImpl(VkDevice device, const uint8_t *data, size_t size, size_t offset)
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index c87704d..6bbfd9b 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -35,6 +35,25 @@
namespace rx
{
+namespace
+{
+
+VkIndexType GetVkIndexType(GLenum glIndexType)
+{
+ switch (glIndexType)
+ {
+ case GL_UNSIGNED_SHORT:
+ return VK_INDEX_TYPE_UINT16;
+ case GL_UNSIGNED_INT:
+ return VK_INDEX_TYPE_UINT32;
+ default:
+ UNREACHABLE();
+ return VK_INDEX_TYPE_MAX_ENUM;
+ }
+}
+
+} // anonymous namespace
+
ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
: ContextImpl(state), mRenderer(renderer), mCurrentDrawMode(GL_NONE)
{
@@ -265,7 +284,7 @@
return gl::NoError();
}
-gl::Error ContextVk::drawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count)
+gl::Error ContextVk::setupDraw(const gl::Context *context, GLenum mode)
{
if (mode != mCurrentDrawMode)
{
@@ -323,11 +342,21 @@
// TODO(jmadill): the queue serial should be bound to the pipeline.
setQueueSerial(queueSerial);
commandBuffer->bindVertexBuffers(0, vertexHandles, vertexOffsets);
- commandBuffer->draw(count, 1, first, 0);
return gl::NoError();
}
+gl::Error ContextVk::drawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count)
+{
+ ANGLE_TRY(setupDraw(context, mode));
+
+ vk::CommandBuffer *commandBuffer = nullptr;
+ ANGLE_TRY(mRenderer->getStartedCommandBuffer(&commandBuffer));
+
+ commandBuffer->draw(count, 1, first, 0);
+ return gl::NoError();
+}
+
gl::Error ContextVk::drawArraysInstanced(const gl::Context *context,
GLenum mode,
GLint first,
@@ -344,8 +373,35 @@
GLenum type,
const void *indices)
{
- UNIMPLEMENTED();
- return gl::InternalError();
+ ANGLE_TRY(setupDraw(context, mode));
+
+ if (indices)
+ {
+ // TODO(jmadill): Buffer offsets and immediate data.
+ UNIMPLEMENTED();
+ return gl::InternalError() << "Only zero-offset index buffers are currently implemented.";
+ }
+
+ if (type == GL_UNSIGNED_BYTE)
+ {
+ // TODO(jmadill): Index translation.
+ UNIMPLEMENTED();
+ return gl::InternalError() << "Unsigned byte translation is not yet implemented.";
+ }
+
+ vk::CommandBuffer *commandBuffer = nullptr;
+ ANGLE_TRY(mRenderer->getStartedCommandBuffer(&commandBuffer));
+
+ const gl::Buffer *elementArrayBuffer =
+ mState.getState().getVertexArray()->getElementArrayBuffer().get();
+ ASSERT(elementArrayBuffer);
+
+ BufferVk *elementArrayBufferVk = GetImplAs<BufferVk>(elementArrayBuffer);
+
+ commandBuffer->bindIndexBuffer(elementArrayBufferVk->getVkBuffer(), 0, GetVkIndexType(type));
+ commandBuffer->drawIndexed(count, 1, 0, 0, 0);
+
+ return gl::NoError();
}
gl::Error ContextVk::drawElementsInstanced(const gl::Context *context,
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.h b/src/libANGLE/renderer/vulkan/ContextVk.h
index 76ee819..cdf2ccc 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.h
+++ b/src/libANGLE/renderer/vulkan/ContextVk.h
@@ -150,6 +150,7 @@
private:
gl::Error initPipeline(const gl::Context *context);
+ gl::Error setupDraw(const gl::Context *context, GLenum mode);
RendererVk *mRenderer;
vk::Pipeline mCurrentPipeline;
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index 9602dca..b8095dc 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -530,6 +530,7 @@
outCaps->maxTextureImageUnits = 1;
outCaps->maxCombinedTextureImageUnits = 1;
outCaps->max2DTextureSize = 1024;
+ outCaps->maxElementIndex = std::numeric_limits<GLuint>::max() - 1;
// Enable this for simple buffer readback testing, but some functionality is missing.
// TODO(jmadill): Support full mapBufferRange extension.
diff --git a/src/libANGLE/renderer/vulkan/renderervk_utils.cpp b/src/libANGLE/renderer/vulkan/renderervk_utils.cpp
index 797df34..e8db5b6 100644
--- a/src/libANGLE/renderer/vulkan/renderervk_utils.cpp
+++ b/src/libANGLE/renderer/vulkan/renderervk_utils.cpp
@@ -428,6 +428,16 @@
vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, firstInstance);
}
+void CommandBuffer::drawIndexed(uint32_t indexCount,
+ uint32_t instanceCount,
+ uint32_t firstIndex,
+ int32_t vertexOffset,
+ uint32_t firstInstance)
+{
+ ASSERT(valid());
+ vkCmdDrawIndexed(mHandle, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
+}
+
void CommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint,
const vk::Pipeline &pipeline)
{
@@ -444,6 +454,14 @@
buffers.data(), offsets.data());
}
+void CommandBuffer::bindIndexBuffer(const vk::Buffer &buffer,
+ VkDeviceSize offset,
+ VkIndexType indexType)
+{
+ ASSERT(valid());
+ vkCmdBindIndexBuffer(mHandle, buffer.getHandle(), offset, indexType);
+}
+
// Image implementation.
Image::Image() : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED)
{
diff --git a/src/libANGLE/renderer/vulkan/renderervk_utils.h b/src/libANGLE/renderer/vulkan/renderervk_utils.h
index 62855e7..df1e621 100644
--- a/src/libANGLE/renderer/vulkan/renderervk_utils.h
+++ b/src/libANGLE/renderer/vulkan/renderervk_utils.h
@@ -83,6 +83,7 @@
namespace vk
{
+class Buffer;
class DeviceMemory;
class Framebuffer;
class Image;
@@ -230,10 +231,17 @@
uint32_t firstVertex,
uint32_t firstInstance);
+ void drawIndexed(uint32_t indexCount,
+ uint32_t instanceCount,
+ uint32_t firstIndex,
+ int32_t vertexOffset,
+ uint32_t firstInstance);
+
void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const vk::Pipeline &pipeline);
void bindVertexBuffers(uint32_t firstBinding,
const std::vector<VkBuffer> &buffers,
const std::vector<VkDeviceSize> &offsets);
+ void bindIndexBuffer(const vk::Buffer &buffer, VkDeviceSize offset, VkIndexType indexType);
private:
bool mStarted;