Commit 360098d5 by Luc Ferron Committed by Commit Bot

Vulkan: Implement GL_LINE_LOOP support for non-indexed draw calls

Line loops aren't supported in Vulkan directly, so we use line strips with an indexed buffer to emulate them. To hide the complexity of that, I've created the LineLoopHandler class in vk_utils. Bug: angleproject:2335 Change-Id: Id3e020d27e5265565e61e96d3fd0187c4fe2b152 Reviewed-on: https://chromium-review.googlesource.com/931421 Commit-Queue: Luc Ferron <lucferron@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 339f65bb
......@@ -84,6 +84,7 @@ void ContextVk::onDestroy(const gl::Context *context)
mDescriptorPool.destroy(device);
mStreamingVertexData.destroy(device);
mLineLoopHandler.destroy(device);
}
gl::Error ContextVk::initialize()
......@@ -264,7 +265,16 @@ gl::Error ContextVk::drawArrays(const gl::Context *context, GLenum mode, GLint f
{
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(setupDraw(context, mode, DrawType::Arrays, first, first + count - 1, &commandBuffer));
if (mode == GL_LINE_LOOP)
{
ANGLE_TRY(mLineLoopHandler.draw(this, first, count, commandBuffer));
}
else
{
commandBuffer->draw(count, 1, first, 0);
}
return gl::NoError();
}
......
......@@ -191,6 +191,8 @@ class ContextVk : public ContextImpl
VkClearValue mClearDepthStencilValue;
StreamingBuffer mStreamingVertexData;
vk::LineLoopHandler mLineLoopHandler;
};
} // namespace rx
......
......@@ -17,7 +17,6 @@
namespace rx
{
StreamingBuffer::StreamingBuffer(VkBufferUsageFlags usage, size_t minSize)
: mUsage(usage),
mMinSize(minSize),
......@@ -33,7 +32,7 @@ StreamingBuffer::~StreamingBuffer()
}
gl::Error StreamingBuffer::allocate(ContextVk *context,
size_t allocationSize,
size_t sizeInBytes,
uint8_t **ptrOut,
VkBuffer *handleOut,
VkDeviceSize *offsetOut)
......@@ -45,7 +44,7 @@ gl::Error StreamingBuffer::allocate(ContextVk *context,
updateQueueSerial(renderer->getCurrentQueueSerial());
angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextWriteOffset;
checkedNextWriteOffset += allocationSize;
checkedNextWriteOffset += sizeInBytes;
if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
{
......@@ -63,7 +62,7 @@ gl::Error StreamingBuffer::allocate(ContextVk *context,
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.size = std::max(allocationSize, mMinSize);
createInfo.size = std::max(sizeInBytes, mMinSize);
createInfo.usage = mUsage;
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
......@@ -82,7 +81,7 @@ gl::Error StreamingBuffer::allocate(ContextVk *context,
ASSERT(mMappedMemory);
*ptrOut = mMappedMemory + mNextWriteOffset;
*offsetOut = mNextWriteOffset;
mNextWriteOffset += allocationSize;
mNextWriteOffset += sizeInBytes;
return gl::NoError();
}
......
......@@ -20,6 +20,9 @@ namespace rx
namespace
{
constexpr int kLineLoopStreamingBufferMinSize = 1024 * 1024;
GLenum DefaultGLErrorCode(VkResult result)
{
switch (result)
......@@ -597,6 +600,14 @@ void CommandBuffer::bindIndexBuffer(const vk::Buffer &buffer,
vkCmdBindIndexBuffer(mHandle, buffer.getHandle(), offset, indexType);
}
void CommandBuffer::bindIndexBuffer(const VkBuffer &buffer,
VkDeviceSize offset,
VkIndexType indexType)
{
ASSERT(valid());
vkCmdBindIndexBuffer(mHandle, buffer, offset, indexType);
}
void CommandBuffer::bindDescriptorSets(VkPipelineBindPoint bindPoint,
const vk::PipelineLayout &layout,
uint32_t firstSet,
......@@ -1309,6 +1320,73 @@ void GarbageObject::destroy(VkDevice device)
}
}
LineLoopHandler::LineLoopHandler()
: mStreamingLineLoopIndicesData(
new StreamingBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, kLineLoopStreamingBufferMinSize)),
mLineLoopIndexBuffer(VK_NULL_HANDLE),
mLineLoopIndexBufferOffset(VK_NULL_HANDLE)
{
}
LineLoopHandler::~LineLoopHandler() = default;
gl::Error LineLoopHandler::bindLineLoopIndexBuffer(ContextVk *contextVk,
int firstVertex,
int count,
vk::CommandBuffer **commandBuffer)
{
int lastVertex = firstVertex + count;
if (mLineLoopIndexBuffer == VK_NULL_HANDLE || !mLineLoopBufferFirstIndex.valid() ||
!mLineLoopBufferLastIndex.valid() || mLineLoopBufferFirstIndex != firstVertex ||
mLineLoopBufferLastIndex != lastVertex)
{
uint32_t *indices = nullptr;
ANGLE_TRY(mStreamingLineLoopIndicesData->allocate(
contextVk, sizeof(uint32_t) * (count + 1), reinterpret_cast<uint8_t **>(&indices),
&mLineLoopIndexBuffer, &mLineLoopIndexBufferOffset));
auto unsignedFirstVertex = static_cast<uint32_t>(firstVertex);
for (auto vertexIndex = unsignedFirstVertex; vertexIndex < (count + unsignedFirstVertex);
vertexIndex++)
{
*indices++ = vertexIndex;
}
*indices = unsignedFirstVertex;
// Since we are not using the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT flag when creating the
// device memory in the StreamingBuffer, we always need to make sure we flush it after
// writing.
ANGLE_TRY(mStreamingLineLoopIndicesData->flush(contextVk));
mLineLoopBufferFirstIndex = firstVertex;
mLineLoopBufferLastIndex = lastVertex;
}
(*commandBuffer)
->bindIndexBuffer(mLineLoopIndexBuffer, mLineLoopIndexBufferOffset, VK_INDEX_TYPE_UINT32);
return gl::NoError();
}
void LineLoopHandler::destroy(VkDevice device)
{
mStreamingLineLoopIndicesData->destroy(device);
}
gl::Error LineLoopHandler::draw(ContextVk *contextVk,
int firstVertex,
int count,
CommandBuffer *commandBuffer)
{
ANGLE_TRY(bindLineLoopIndexBuffer(contextVk, firstVertex, count, &commandBuffer));
// Our first index is always 0 because that's how we set it up in the
// bindLineLoopIndexBuffer.
commandBuffer->drawIndexed(count + 1, 1, 0, 0, 0);
return gl::NoError();
}
} // namespace vk
namespace gl_vk
......@@ -1330,8 +1408,6 @@ VkPrimitiveTopology GetPrimitiveTopology(GLenum mode)
case GL_TRIANGLE_STRIP:
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
case GL_LINE_LOOP:
// TODO(jmadill): Implement line loop support.
UNIMPLEMENTED();
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
default:
UNREACHABLE();
......
......@@ -55,6 +55,7 @@ class RenderTargetVk;
class RendererVk;
class ResourceVk;
class RenderPassCache;
class StreamingBuffer;
enum class DrawType
{
......@@ -375,6 +376,7 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
const VkBuffer *buffers,
const VkDeviceSize *offsets);
void bindIndexBuffer(const vk::Buffer &buffer, VkDeviceSize offset, VkIndexType indexType);
void bindIndexBuffer(const VkBuffer &buffer, VkDeviceSize offset, VkIndexType indexType);
void bindDescriptorSets(VkPipelineBindPoint bindPoint,
const vk::PipelineLayout &layout,
uint32_t firstSet,
......@@ -668,6 +670,33 @@ Error AllocateImageMemory(RendererVk *renderer,
DeviceMemory *deviceMemoryOut,
size_t *requiredSizeOut);
// This class responsibility is to bind an indexed buffer needed to support line loops in Vulkan.
// In the setup phase of drawing, the bindLineLoopIndexBuffer method should be called with the
// first/last vertex and the current commandBuffer. If the user wants to draw a loop between [v1,
// v2, v3], we will create an indexed buffer with these indexes: [0, 1, 2, 3, 0] to emulate the
// loop.
class LineLoopHandler final : angle::NonCopyable
{
public:
LineLoopHandler();
~LineLoopHandler();
void destroy(VkDevice device);
gl::Error draw(ContextVk *contextVk, int firstVertex, int count, CommandBuffer *commandBuffer);
private:
gl::Error bindLineLoopIndexBuffer(ContextVk *contextVk,
int firstVertex,
int count,
vk::CommandBuffer **commandBuffer);
std::unique_ptr<StreamingBuffer> mStreamingLineLoopIndicesData;
VkBuffer mLineLoopIndexBuffer;
VkDeviceSize mLineLoopIndexBufferOffset;
Optional<int> mLineLoopBufferFirstIndex;
Optional<int> mLineLoopBufferLastIndex;
};
} // namespace vk
namespace gl_vk
......
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