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) ...@@ -84,6 +84,7 @@ void ContextVk::onDestroy(const gl::Context *context)
mDescriptorPool.destroy(device); mDescriptorPool.destroy(device);
mStreamingVertexData.destroy(device); mStreamingVertexData.destroy(device);
mLineLoopHandler.destroy(device);
} }
gl::Error ContextVk::initialize() gl::Error ContextVk::initialize()
...@@ -264,7 +265,16 @@ gl::Error ContextVk::drawArrays(const gl::Context *context, GLenum mode, GLint f ...@@ -264,7 +265,16 @@ gl::Error ContextVk::drawArrays(const gl::Context *context, GLenum mode, GLint f
{ {
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(setupDraw(context, mode, DrawType::Arrays, first, first + count - 1, &commandBuffer)); 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); commandBuffer->draw(count, 1, first, 0);
}
return gl::NoError(); return gl::NoError();
} }
......
...@@ -191,6 +191,8 @@ class ContextVk : public ContextImpl ...@@ -191,6 +191,8 @@ class ContextVk : public ContextImpl
VkClearValue mClearDepthStencilValue; VkClearValue mClearDepthStencilValue;
StreamingBuffer mStreamingVertexData; StreamingBuffer mStreamingVertexData;
vk::LineLoopHandler mLineLoopHandler;
}; };
} // namespace rx } // namespace rx
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
namespace rx namespace rx
{ {
StreamingBuffer::StreamingBuffer(VkBufferUsageFlags usage, size_t minSize) StreamingBuffer::StreamingBuffer(VkBufferUsageFlags usage, size_t minSize)
: mUsage(usage), : mUsage(usage),
mMinSize(minSize), mMinSize(minSize),
...@@ -33,7 +32,7 @@ StreamingBuffer::~StreamingBuffer() ...@@ -33,7 +32,7 @@ StreamingBuffer::~StreamingBuffer()
} }
gl::Error StreamingBuffer::allocate(ContextVk *context, gl::Error StreamingBuffer::allocate(ContextVk *context,
size_t allocationSize, size_t sizeInBytes,
uint8_t **ptrOut, uint8_t **ptrOut,
VkBuffer *handleOut, VkBuffer *handleOut,
VkDeviceSize *offsetOut) VkDeviceSize *offsetOut)
...@@ -45,7 +44,7 @@ gl::Error StreamingBuffer::allocate(ContextVk *context, ...@@ -45,7 +44,7 @@ gl::Error StreamingBuffer::allocate(ContextVk *context,
updateQueueSerial(renderer->getCurrentQueueSerial()); updateQueueSerial(renderer->getCurrentQueueSerial());
angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextWriteOffset; angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextWriteOffset;
checkedNextWriteOffset += allocationSize; checkedNextWriteOffset += sizeInBytes;
if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize) if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
{ {
...@@ -63,7 +62,7 @@ gl::Error StreamingBuffer::allocate(ContextVk *context, ...@@ -63,7 +62,7 @@ gl::Error StreamingBuffer::allocate(ContextVk *context,
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.pNext = nullptr; createInfo.pNext = nullptr;
createInfo.flags = 0; createInfo.flags = 0;
createInfo.size = std::max(allocationSize, mMinSize); createInfo.size = std::max(sizeInBytes, mMinSize);
createInfo.usage = mUsage; createInfo.usage = mUsage;
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0; createInfo.queueFamilyIndexCount = 0;
...@@ -82,7 +81,7 @@ gl::Error StreamingBuffer::allocate(ContextVk *context, ...@@ -82,7 +81,7 @@ gl::Error StreamingBuffer::allocate(ContextVk *context,
ASSERT(mMappedMemory); ASSERT(mMappedMemory);
*ptrOut = mMappedMemory + mNextWriteOffset; *ptrOut = mMappedMemory + mNextWriteOffset;
*offsetOut = mNextWriteOffset; *offsetOut = mNextWriteOffset;
mNextWriteOffset += allocationSize; mNextWriteOffset += sizeInBytes;
return gl::NoError(); return gl::NoError();
} }
......
...@@ -20,6 +20,9 @@ namespace rx ...@@ -20,6 +20,9 @@ namespace rx
namespace namespace
{ {
constexpr int kLineLoopStreamingBufferMinSize = 1024 * 1024;
GLenum DefaultGLErrorCode(VkResult result) GLenum DefaultGLErrorCode(VkResult result)
{ {
switch (result) switch (result)
...@@ -597,6 +600,14 @@ void CommandBuffer::bindIndexBuffer(const vk::Buffer &buffer, ...@@ -597,6 +600,14 @@ void CommandBuffer::bindIndexBuffer(const vk::Buffer &buffer,
vkCmdBindIndexBuffer(mHandle, buffer.getHandle(), offset, indexType); 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, void CommandBuffer::bindDescriptorSets(VkPipelineBindPoint bindPoint,
const vk::PipelineLayout &layout, const vk::PipelineLayout &layout,
uint32_t firstSet, uint32_t firstSet,
...@@ -1309,6 +1320,73 @@ void GarbageObject::destroy(VkDevice device) ...@@ -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 vk
namespace gl_vk namespace gl_vk
...@@ -1330,8 +1408,6 @@ VkPrimitiveTopology GetPrimitiveTopology(GLenum mode) ...@@ -1330,8 +1408,6 @@ VkPrimitiveTopology GetPrimitiveTopology(GLenum mode)
case GL_TRIANGLE_STRIP: case GL_TRIANGLE_STRIP:
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
case GL_LINE_LOOP: case GL_LINE_LOOP:
// TODO(jmadill): Implement line loop support.
UNIMPLEMENTED();
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
default: default:
UNREACHABLE(); UNREACHABLE();
......
...@@ -55,6 +55,7 @@ class RenderTargetVk; ...@@ -55,6 +55,7 @@ class RenderTargetVk;
class RendererVk; class RendererVk;
class ResourceVk; class ResourceVk;
class RenderPassCache; class RenderPassCache;
class StreamingBuffer;
enum class DrawType enum class DrawType
{ {
...@@ -375,6 +376,7 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer> ...@@ -375,6 +376,7 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
const VkBuffer *buffers, const VkBuffer *buffers,
const VkDeviceSize *offsets); const VkDeviceSize *offsets);
void bindIndexBuffer(const vk::Buffer &buffer, VkDeviceSize offset, VkIndexType indexType); void bindIndexBuffer(const vk::Buffer &buffer, VkDeviceSize offset, VkIndexType indexType);
void bindIndexBuffer(const VkBuffer &buffer, VkDeviceSize offset, VkIndexType indexType);
void bindDescriptorSets(VkPipelineBindPoint bindPoint, void bindDescriptorSets(VkPipelineBindPoint bindPoint,
const vk::PipelineLayout &layout, const vk::PipelineLayout &layout,
uint32_t firstSet, uint32_t firstSet,
...@@ -668,6 +670,33 @@ Error AllocateImageMemory(RendererVk *renderer, ...@@ -668,6 +670,33 @@ Error AllocateImageMemory(RendererVk *renderer,
DeviceMemory *deviceMemoryOut, DeviceMemory *deviceMemoryOut,
size_t *requiredSizeOut); 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 vk
namespace gl_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