Commit d03a849d by Jamie Madill Committed by Commit Bot

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: 's avatarFrank Henigman <fjhenigman@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent 035fd6b3
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "libANGLE/renderer/vulkan/BufferVk.h" #include "libANGLE/renderer/vulkan/BufferVk.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/utilities.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
...@@ -170,8 +171,19 @@ gl::Error BufferVk::getIndexRange(const gl::Context *context, ...@@ -170,8 +171,19 @@ gl::Error BufferVk::getIndexRange(const gl::Context *context,
bool primitiveRestartEnabled, bool primitiveRestartEnabled,
gl::IndexRange *outRange) gl::IndexRange *outRange)
{ {
UNIMPLEMENTED(); VkDevice device = GetImplAs<ContextVk>(context)->getDevice();
return gl::InternalError();
// 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) vk::Error BufferVk::setDataImpl(VkDevice device, const uint8_t *data, size_t size, size_t offset)
......
...@@ -35,6 +35,25 @@ ...@@ -35,6 +35,25 @@
namespace rx 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) ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
: ContextImpl(state), mRenderer(renderer), mCurrentDrawMode(GL_NONE) : ContextImpl(state), mRenderer(renderer), mCurrentDrawMode(GL_NONE)
{ {
...@@ -265,7 +284,7 @@ gl::Error ContextVk::initPipeline(const gl::Context *context) ...@@ -265,7 +284,7 @@ gl::Error ContextVk::initPipeline(const gl::Context *context)
return gl::NoError(); 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) if (mode != mCurrentDrawMode)
{ {
...@@ -323,11 +342,21 @@ gl::Error ContextVk::drawArrays(const gl::Context *context, GLenum mode, GLint f ...@@ -323,11 +342,21 @@ gl::Error ContextVk::drawArrays(const gl::Context *context, GLenum mode, GLint f
// TODO(jmadill): the queue serial should be bound to the pipeline. // TODO(jmadill): the queue serial should be bound to the pipeline.
setQueueSerial(queueSerial); setQueueSerial(queueSerial);
commandBuffer->bindVertexBuffers(0, vertexHandles, vertexOffsets); commandBuffer->bindVertexBuffers(0, vertexHandles, vertexOffsets);
commandBuffer->draw(count, 1, first, 0);
return gl::NoError(); 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, gl::Error ContextVk::drawArraysInstanced(const gl::Context *context,
GLenum mode, GLenum mode,
GLint first, GLint first,
...@@ -344,8 +373,35 @@ gl::Error ContextVk::drawElements(const gl::Context *context, ...@@ -344,8 +373,35 @@ gl::Error ContextVk::drawElements(const gl::Context *context,
GLenum type, GLenum type,
const void *indices) const void *indices)
{ {
UNIMPLEMENTED(); ANGLE_TRY(setupDraw(context, mode));
return gl::InternalError();
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, gl::Error ContextVk::drawElementsInstanced(const gl::Context *context,
......
...@@ -150,6 +150,7 @@ class ContextVk : public ContextImpl, public ResourceVk ...@@ -150,6 +150,7 @@ class ContextVk : public ContextImpl, public ResourceVk
private: private:
gl::Error initPipeline(const gl::Context *context); gl::Error initPipeline(const gl::Context *context);
gl::Error setupDraw(const gl::Context *context, GLenum mode);
RendererVk *mRenderer; RendererVk *mRenderer;
vk::Pipeline mCurrentPipeline; vk::Pipeline mCurrentPipeline;
......
...@@ -530,6 +530,7 @@ void RendererVk::generateCaps(gl::Caps *outCaps, ...@@ -530,6 +530,7 @@ void RendererVk::generateCaps(gl::Caps *outCaps,
outCaps->maxTextureImageUnits = 1; outCaps->maxTextureImageUnits = 1;
outCaps->maxCombinedTextureImageUnits = 1; outCaps->maxCombinedTextureImageUnits = 1;
outCaps->max2DTextureSize = 1024; outCaps->max2DTextureSize = 1024;
outCaps->maxElementIndex = std::numeric_limits<GLuint>::max() - 1;
// Enable this for simple buffer readback testing, but some functionality is missing. // Enable this for simple buffer readback testing, but some functionality is missing.
// TODO(jmadill): Support full mapBufferRange extension. // TODO(jmadill): Support full mapBufferRange extension.
......
...@@ -428,6 +428,16 @@ void CommandBuffer::draw(uint32_t vertexCount, ...@@ -428,6 +428,16 @@ void CommandBuffer::draw(uint32_t vertexCount,
vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, firstInstance); 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, void CommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint,
const vk::Pipeline &pipeline) const vk::Pipeline &pipeline)
{ {
...@@ -444,6 +454,14 @@ void CommandBuffer::bindVertexBuffers(uint32_t firstBinding, ...@@ -444,6 +454,14 @@ void CommandBuffer::bindVertexBuffers(uint32_t firstBinding,
buffers.data(), offsets.data()); 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 implementation.
Image::Image() : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED) Image::Image() : mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED)
{ {
......
...@@ -83,6 +83,7 @@ class ResourceVk ...@@ -83,6 +83,7 @@ class ResourceVk
namespace vk namespace vk
{ {
class Buffer;
class DeviceMemory; class DeviceMemory;
class Framebuffer; class Framebuffer;
class Image; class Image;
...@@ -230,10 +231,17 @@ class CommandBuffer final : public WrappedObject<CommandBuffer, VkCommandBuffer> ...@@ -230,10 +231,17 @@ class CommandBuffer final : public WrappedObject<CommandBuffer, VkCommandBuffer>
uint32_t firstVertex, uint32_t firstVertex,
uint32_t firstInstance); 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 bindPipeline(VkPipelineBindPoint pipelineBindPoint, const vk::Pipeline &pipeline);
void bindVertexBuffers(uint32_t firstBinding, void bindVertexBuffers(uint32_t firstBinding,
const std::vector<VkBuffer> &buffers, const std::vector<VkBuffer> &buffers,
const std::vector<VkDeviceSize> &offsets); const std::vector<VkDeviceSize> &offsets);
void bindIndexBuffer(const vk::Buffer &buffer, VkDeviceSize offset, VkIndexType indexType);
private: private:
bool mStarted; bool mStarted;
......
...@@ -235,7 +235,7 @@ TEST_P(SimpleOperationTest, DrawQuad) ...@@ -235,7 +235,7 @@ TEST_P(SimpleOperationTest, DrawQuad)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Simple repeatd draw and swap test. // Simple repeated draw and swap test.
TEST_P(SimpleOperationTest, DrawQuadAndSwap) TEST_P(SimpleOperationTest, DrawQuadAndSwap)
{ {
const std::string &vertexShader = const std::string &vertexShader =
...@@ -262,6 +262,28 @@ TEST_P(SimpleOperationTest, DrawQuadAndSwap) ...@@ -262,6 +262,28 @@ TEST_P(SimpleOperationTest, DrawQuadAndSwap)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Simple indexed quad test.
TEST_P(SimpleOperationTest, DrawIndexedQuad)
{
const std::string vertexShader =
"attribute vec3 position;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 1);\n"
"}";
const std::string fragmentShader =
"void main()\n"
"{\n"
" gl_FragColor = vec4(0, 1, 0, 1);\n"
"}";
ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
drawIndexedQuad(program.get(), "position", 0.5f, 1.0f, true);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Tests a shader program with more than one vertex attribute, with vertex buffers. // Tests a shader program with more than one vertex attribute, with vertex buffers.
TEST_P(SimpleOperationTest, ThreeVertexAttributes) TEST_P(SimpleOperationTest, ThreeVertexAttributes)
{ {
......
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