Commit c3755fc5 by Jamie Madill Committed by Commit Bot

Vulkan: Move Streaming data to VertexArrayVk.

Instead of the ContextVk owning the translations for the various attributes, make the VertexArrayVk own them. This way they can handle the dirty bit state notifications directly instead of needing their own Observers. Bug: angleproject:2389 Change-Id: I5e571ba6c563e820a4c0d5f92db35031e6f2428a Reviewed-on: https://chromium-review.googlesource.com/989258 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent e7b3fe21
...@@ -38,44 +38,16 @@ ...@@ -38,44 +38,16 @@
namespace rx namespace rx
{ {
namespace
{
VkIndexType GetVkIndexType(GLenum glIndexType)
{
switch (glIndexType)
{
case GL_UNSIGNED_BYTE:
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;
}
}
constexpr size_t kDynamicVertexDataSize = 1024 * 1024;
constexpr size_t kDynamicIndexDataSize = 1024 * 8;
} // anonymous namespace
ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer) ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
: ContextImpl(state), : ContextImpl(state),
mRenderer(renderer), mRenderer(renderer),
mCurrentDrawMode(GL_NONE), mCurrentDrawMode(GL_NONE),
mDynamicDescriptorPool(), mDynamicDescriptorPool(),
mVertexArrayDirty(false),
mTexturesDirty(false), mTexturesDirty(false),
mDynamicVertexData(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, kDynamicVertexDataSize), mVertexArrayBindingHasChanged(false)
mDynamicIndexData(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, kDynamicIndexDataSize)
{ {
memset(&mClearColorValue, 0, sizeof(mClearColorValue)); memset(&mClearColorValue, 0, sizeof(mClearColorValue));
memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue)); memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue));
mDynamicVertexData.init(1);
mDynamicIndexData.init(1);
} }
ContextVk::~ContextVk() ContextVk::~ContextVk()
...@@ -84,12 +56,7 @@ ContextVk::~ContextVk() ...@@ -84,12 +56,7 @@ ContextVk::~ContextVk()
void ContextVk::onDestroy(const gl::Context *context) void ContextVk::onDestroy(const gl::Context *context)
{ {
VkDevice device = mRenderer->getDevice();
mDynamicDescriptorPool.destroy(mRenderer); mDynamicDescriptorPool.destroy(mRenderer);
mDynamicVertexData.destroy(device);
mDynamicIndexData.destroy(device);
mLineLoopHandler.destroy(device);
} }
gl::Error ContextVk::initialize() gl::Error ContextVk::initialize()
...@@ -149,8 +116,8 @@ gl::Error ContextVk::initPipeline(const gl::Context *context) ...@@ -149,8 +116,8 @@ gl::Error ContextVk::initPipeline(const gl::Context *context)
gl::Error ContextVk::setupDraw(const gl::Context *context, gl::Error ContextVk::setupDraw(const gl::Context *context,
const gl::DrawCallParams &drawCallParams, const gl::DrawCallParams &drawCallParams,
ResourceVk *elementArrayBufferOverride, vk::CommandGraphNode **drawNodeOut,
vk::CommandBuffer **commandBufferOut) bool *newCommandBufferOut)
{ {
if (drawCallParams.mode() != mCurrentDrawMode) if (drawCallParams.mode() != mCurrentDrawMode)
{ {
...@@ -166,12 +133,9 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, ...@@ -166,12 +133,9 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
const auto &state = mState.getState(); const auto &state = mState.getState();
const gl::Program *programGL = state.getProgram(); const gl::Program *programGL = state.getProgram();
ProgramVk *programVk = vk::GetImpl(programGL); ProgramVk *programVk = vk::GetImpl(programGL);
const gl::VertexArray *vao = state.getVertexArray();
VertexArrayVk *vkVAO = vk::GetImpl(vao);
const auto *drawFBO = state.getDrawFramebuffer(); const auto *drawFBO = state.getDrawFramebuffer();
FramebufferVk *vkFBO = vk::GetImpl(drawFBO); FramebufferVk *vkFBO = vk::GetImpl(drawFBO);
Serial queueSerial = mRenderer->getCurrentQueueSerial(); Serial queueSerial = mRenderer->getCurrentQueueSerial();
uint32_t maxAttrib = programGL->getState().getMaxActiveAttribLocation();
vk::CommandGraphNode *graphNode = nullptr; vk::CommandGraphNode *graphNode = nullptr;
ANGLE_TRY(vkFBO->getCommandGraphNodeForDraw(context, &graphNode)); ANGLE_TRY(vkFBO->getCommandGraphNodeForDraw(context, &graphNode));
...@@ -180,25 +144,17 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, ...@@ -180,25 +144,17 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
if (!graphNode->getInsideRenderPassCommands()->valid()) if (!graphNode->getInsideRenderPassCommands()->valid())
{ {
mVertexArrayDirty = true;
mTexturesDirty = true; mTexturesDirty = true;
*newCommandBufferOut = true;
ANGLE_TRY(graphNode->beginInsideRenderPassRecording(mRenderer, &commandBuffer)); ANGLE_TRY(graphNode->beginInsideRenderPassRecording(mRenderer, &commandBuffer));
} }
else else
{ {
*newCommandBufferOut = mVertexArrayBindingHasChanged;
mVertexArrayBindingHasChanged = false;
commandBuffer = graphNode->getInsideRenderPassCommands(); commandBuffer = graphNode->getInsideRenderPassCommands();
} }
// Ensure any writes to the VAO buffers are flushed before we read from them.
if (mVertexArrayDirty || elementArrayBufferOverride != nullptr)
{
mVertexArrayDirty = false;
vkVAO->updateDrawDependencies(graphNode, programGL->getActiveAttribLocationsMask(),
elementArrayBufferOverride, queueSerial,
drawCallParams.isDrawElements());
}
// Ensure any writes to the textures are flushed before we read from them. // Ensure any writes to the textures are flushed before we read from them.
if (mTexturesDirty) if (mTexturesDirty)
{ {
...@@ -224,9 +180,6 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, ...@@ -224,9 +180,6 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
} }
commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline->get()); commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline->get());
ANGLE_TRY(vkVAO->streamVertexData(context, &mDynamicVertexData, drawCallParams));
commandBuffer->bindVertexBuffers(0, maxAttrib, vkVAO->getCurrentArrayBufferHandles().data(),
vkVAO->getCurrentArrayBufferOffsets().data());
// Update the queue serial for the pipeline object. // Update the queue serial for the pipeline object.
ASSERT(mCurrentPipeline && mCurrentPipeline->valid()); ASSERT(mCurrentPipeline && mCurrentPipeline->valid());
...@@ -251,7 +204,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, ...@@ -251,7 +204,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
programVk->getDynamicOffsets()); programVk->getDynamicOffsets());
} }
*commandBufferOut = commandBuffer; *drawNodeOut = graphNode;
return gl::NoError(); return gl::NoError();
} }
...@@ -259,19 +212,13 @@ gl::Error ContextVk::drawArrays(const gl::Context *context, GLenum mode, GLint f ...@@ -259,19 +212,13 @@ gl::Error ContextVk::drawArrays(const gl::Context *context, GLenum mode, GLint f
{ {
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>(); const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandGraphNode *drawNode = nullptr;
ANGLE_TRY(setupDraw(context, drawCallParams, nullptr, &commandBuffer)); bool newCommands = false;
ANGLE_TRY(setupDraw(context, drawCallParams, &drawNode, &newCommands));
if (mode == GL_LINE_LOOP) const gl::VertexArray *vertexArray = context->getGLState().getVertexArray();
{ VertexArrayVk *vertexArrayVk = vk::GetImpl(vertexArray);
ANGLE_TRY(mLineLoopHandler.createIndexBuffer(this, first, count)); ANGLE_TRY(vertexArrayVk->drawArrays(context, mRenderer, drawCallParams, drawNode, newCommands));
mLineLoopHandler.bindIndexBuffer(VK_INDEX_TYPE_UINT32, &commandBuffer);
ANGLE_TRY(mLineLoopHandler.draw(count, commandBuffer));
}
else
{
commandBuffer->draw(count, 1, first, 0);
}
return gl::NoError(); return gl::NoError();
} }
...@@ -294,80 +241,14 @@ gl::Error ContextVk::drawElements(const gl::Context *context, ...@@ -294,80 +241,14 @@ gl::Error ContextVk::drawElements(const gl::Context *context,
{ {
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>(); const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
gl::VertexArray *vao = mState.getState().getVertexArray(); vk::CommandGraphNode *drawNode = nullptr;
const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); bool newCommands = false;
vk::CommandBuffer *commandBuffer = nullptr; ANGLE_TRY(setupDraw(context, drawCallParams, &drawNode, &newCommands));
if (mode == GL_LINE_LOOP)
{
if (!elementArrayBuffer)
{
UNIMPLEMENTED();
return gl::InternalError() << "Line loop indices in client memory not supported";
}
BufferVk *elementArrayBufferVk = vk::GetImpl(elementArrayBuffer);
ANGLE_TRY(mLineLoopHandler.createIndexBufferFromElementArrayBuffer(
this, elementArrayBufferVk, GetVkIndexType(type), count));
// TODO(fjhenigman): calculate the index range and pass to setupDraw()
ANGLE_TRY(setupDraw(context, drawCallParams, mLineLoopHandler.getLineLoopBufferResource(),
&commandBuffer));
mLineLoopHandler.bindIndexBuffer(GetVkIndexType(type), &commandBuffer);
commandBuffer->drawIndexed(count + 1, 1, 0, 0, 0);
}
else
{
ContextVk *contextVk = vk::GetImpl(context);
gl::IndexRange range;
VkBuffer buffer = VK_NULL_HANDLE;
uint32_t offset = 0;
if (elementArrayBuffer)
{
if (type == GL_UNSIGNED_BYTE)
{
// TODO(fjhenigman): Index format translation.
UNIMPLEMENTED();
return gl::InternalError() << "Unsigned byte translation is not implemented for "
<< "indices in a buffer object";
}
BufferVk *elementArrayBufferVk = vk::GetImpl(elementArrayBuffer);
buffer = elementArrayBufferVk->getVkBuffer().getHandle();
offset = 0;
}
else
{
const GLsizei amount = sizeof(GLushort) * count;
GLubyte *dst = nullptr;
gl::VertexArray *vao = mState.getState().getVertexArray();
VertexArrayVk *vertexArrayVk = vk::GetImpl(vao);
ANGLE_TRY( ANGLE_TRY(
mDynamicIndexData.allocate(contextVk, amount, &dst, &buffer, &offset, nullptr)); vertexArrayVk->drawElements(context, mRenderer, drawCallParams, drawNode, newCommands));
if (type == GL_UNSIGNED_BYTE)
{
// Unsigned bytes don't have direct support in Vulkan so we have to expand the
// memory to a GLushort.
const GLubyte *in = static_cast<const GLubyte *>(indices);
GLushort *expandedDst = reinterpret_cast<GLushort *>(dst);
for (GLsizei index = 0; index < count; index++)
{
expandedDst[index] = static_cast<GLushort>(in[index]);
}
}
else
{
memcpy(dst, indices, amount);
}
ANGLE_TRY(mDynamicIndexData.flush(contextVk));
}
ANGLE_TRY(setupDraw(context, drawCallParams, nullptr, &commandBuffer));
commandBuffer->bindIndexBuffer(buffer, offset, GetVkIndexType(type));
commandBuffer->drawIndexed(count, 1, 0, 0, 0);
}
return gl::NoError(); return gl::NoError();
} }
...@@ -636,7 +517,8 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits ...@@ -636,7 +517,8 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
WARN() << "DIRTY_BIT_RENDERBUFFER_BINDING unimplemented"; WARN() << "DIRTY_BIT_RENDERBUFFER_BINDING unimplemented";
break; break;
case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING: case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
mVertexArrayDirty = true; invalidateCurrentPipeline();
mVertexArrayBindingHasChanged = true;
break; break;
case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING: case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
WARN() << "DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING unimplemented"; WARN() << "DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING unimplemented";
...@@ -823,13 +705,6 @@ void ContextVk::invalidateCurrentPipeline() ...@@ -823,13 +705,6 @@ void ContextVk::invalidateCurrentPipeline()
mCurrentPipeline = nullptr; mCurrentPipeline = nullptr;
} }
void ContextVk::onVertexArrayChange()
{
// TODO(jmadill): Does not handle dependent state changes.
mVertexArrayDirty = true;
invalidateCurrentPipeline();
}
gl::Error ContextVk::dispatchCompute(const gl::Context *context, gl::Error ContextVk::dispatchCompute(const gl::Context *context,
GLuint numGroupsX, GLuint numGroupsX,
GLuint numGroupsY, GLuint numGroupsY,
......
...@@ -155,7 +155,6 @@ class ContextVk : public ContextImpl ...@@ -155,7 +155,6 @@ class ContextVk : public ContextImpl
RendererVk *getRenderer() { return mRenderer; } RendererVk *getRenderer() { return mRenderer; }
void invalidateCurrentPipeline(); void invalidateCurrentPipeline();
void onVertexArrayChange();
DynamicDescriptorPool *getDynamicDescriptorPool(); DynamicDescriptorPool *getDynamicDescriptorPool();
...@@ -167,8 +166,8 @@ class ContextVk : public ContextImpl ...@@ -167,8 +166,8 @@ class ContextVk : public ContextImpl
gl::Error initPipeline(const gl::Context *context); gl::Error initPipeline(const gl::Context *context);
gl::Error setupDraw(const gl::Context *context, gl::Error setupDraw(const gl::Context *context,
const gl::DrawCallParams &drawCallParams, const gl::DrawCallParams &drawCallParams,
ResourceVk *elementArrayBufferOverride, vk::CommandGraphNode **drawNodeOut,
vk::CommandBuffer **commandBufferOut); bool *newCommandBufferOut);
RendererVk *mRenderer; RendererVk *mRenderer;
vk::PipelineAndSerial *mCurrentPipeline; vk::PipelineAndSerial *mCurrentPipeline;
...@@ -183,17 +182,12 @@ class ContextVk : public ContextImpl ...@@ -183,17 +182,12 @@ class ContextVk : public ContextImpl
DynamicDescriptorPool mDynamicDescriptorPool; DynamicDescriptorPool mDynamicDescriptorPool;
// Triggers adding dependencies to the command graph. // Triggers adding dependencies to the command graph.
bool mVertexArrayDirty;
bool mTexturesDirty; bool mTexturesDirty;
bool mVertexArrayBindingHasChanged;
// Cached clear value for color and depth/stencil. // Cached clear value for color and depth/stencil.
VkClearValue mClearColorValue; VkClearValue mClearColorValue;
VkClearValue mClearDepthStencilValue; VkClearValue mClearDepthStencilValue;
DynamicBuffer mDynamicVertexData;
DynamicBuffer mDynamicIndexData;
vk::LineLoopHandler mLineLoopHandler;
}; };
} // namespace rx } // namespace rx
......
...@@ -44,7 +44,7 @@ bool DynamicBuffer::valid() ...@@ -44,7 +44,7 @@ bool DynamicBuffer::valid()
return mAlignment > 0; return mAlignment > 0;
} }
vk::Error DynamicBuffer::allocate(ContextVk *context, vk::Error DynamicBuffer::allocate(RendererVk *renderer,
size_t sizeInBytes, size_t sizeInBytes,
uint8_t **ptrOut, uint8_t **ptrOut,
VkBuffer *handleOut, VkBuffer *handleOut,
...@@ -52,11 +52,7 @@ vk::Error DynamicBuffer::allocate(ContextVk *context, ...@@ -52,11 +52,7 @@ vk::Error DynamicBuffer::allocate(ContextVk *context,
bool *outNewBufferAllocated) bool *outNewBufferAllocated)
{ {
ASSERT(valid()); ASSERT(valid());
RendererVk *renderer = context->getRenderer(); VkDevice device = renderer->getDevice();
// TODO(fjhenigman): Update this when we have buffers that need to
// persist longer than one frame.
updateQueueSerial(renderer->getCurrentQueueSerial());
size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment); size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
...@@ -65,16 +61,15 @@ vk::Error DynamicBuffer::allocate(ContextVk *context, ...@@ -65,16 +61,15 @@ vk::Error DynamicBuffer::allocate(ContextVk *context,
if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize) if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
{ {
VkDevice device = context->getDevice();
if (mMappedMemory) if (mMappedMemory)
{ {
ANGLE_TRY(flush(context)); ANGLE_TRY(flush(device));
mMemory.unmap(device); mMemory.unmap(device);
mMappedMemory = nullptr; mMappedMemory = nullptr;
} }
renderer->releaseResource(*this, &mBuffer); Serial currentSerial = renderer->getCurrentQueueSerial();
renderer->releaseResource(*this, &mMemory); renderer->releaseObject(currentSerial, &mBuffer);
renderer->releaseObject(currentSerial, &mMemory);
VkBufferCreateInfo createInfo; VkBufferCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
...@@ -121,7 +116,7 @@ vk::Error DynamicBuffer::allocate(ContextVk *context, ...@@ -121,7 +116,7 @@ vk::Error DynamicBuffer::allocate(ContextVk *context,
return vk::NoError(); return vk::NoError();
} }
vk::Error DynamicBuffer::flush(ContextVk *context) vk::Error DynamicBuffer::flush(VkDevice device)
{ {
if (mNextWriteOffset > mLastFlushOffset) if (mNextWriteOffset > mLastFlushOffset)
{ {
...@@ -131,7 +126,7 @@ vk::Error DynamicBuffer::flush(ContextVk *context) ...@@ -131,7 +126,7 @@ vk::Error DynamicBuffer::flush(ContextVk *context)
range.memory = mMemory.getHandle(); range.memory = mMemory.getHandle();
range.offset = mLastFlushOffset; range.offset = mLastFlushOffset;
range.size = mNextWriteOffset - mLastFlushOffset; range.size = mNextWriteOffset - mLastFlushOffset;
ANGLE_VK_TRY(vkFlushMappedMemoryRanges(context->getDevice(), 1, &range)); ANGLE_VK_TRY(vkFlushMappedMemoryRanges(device, 1, &range));
mLastFlushOffset = mNextWriteOffset; mLastFlushOffset = mNextWriteOffset;
} }
......
...@@ -20,16 +20,17 @@ class DynamicBuffer : public ResourceVk ...@@ -20,16 +20,17 @@ class DynamicBuffer : public ResourceVk
{ {
public: public:
DynamicBuffer(VkBufferUsageFlags usage, size_t minSize); DynamicBuffer(VkBufferUsageFlags usage, size_t minSize);
~DynamicBuffer();
void init(size_t alignment); void init(size_t alignment);
bool valid(); bool valid();
~DynamicBuffer(); vk::Error allocate(RendererVk *renderer,
vk::Error allocate(ContextVk *context,
size_t sizeInBytes, size_t sizeInBytes,
uint8_t **ptrOut, uint8_t **ptrOut,
VkBuffer *handleOut, VkBuffer *handleOut,
uint32_t *offsetOut, uint32_t *offsetOut,
bool *outNewBufferAllocated); bool *outNewBufferAllocated);
vk::Error flush(ContextVk *context); vk::Error flush(VkDevice device);
void destroy(VkDevice device); void destroy(VkDevice device);
VkBuffer getCurrentBufferHandle() const; VkBuffer getCurrentBufferHandle() const;
......
...@@ -113,8 +113,8 @@ void ReadFromDefaultUniformBlock(int componentCount, ...@@ -113,8 +113,8 @@ void ReadFromDefaultUniformBlock(int componentCount,
} }
} }
vk::Error SyncDefaultUniformBlock(ContextVk *contextVk, vk::Error SyncDefaultUniformBlock(RendererVk *renderer,
DynamicBuffer &dynamicBuffer, DynamicBuffer *dynamicBuffer,
const angle::MemoryBuffer &bufferData, const angle::MemoryBuffer &bufferData,
uint32_t *outOffset, uint32_t *outOffset,
bool *outBufferModified) bool *outBufferModified)
...@@ -123,11 +123,11 @@ vk::Error SyncDefaultUniformBlock(ContextVk *contextVk, ...@@ -123,11 +123,11 @@ vk::Error SyncDefaultUniformBlock(ContextVk *contextVk,
uint8_t *data = nullptr; uint8_t *data = nullptr;
VkBuffer *outBuffer = nullptr; VkBuffer *outBuffer = nullptr;
uint32_t offset; uint32_t offset;
ANGLE_TRY(dynamicBuffer.allocate(contextVk, bufferData.size(), &data, outBuffer, &offset, ANGLE_TRY(dynamicBuffer->allocate(renderer, bufferData.size(), &data, outBuffer, &offset,
outBufferModified)); outBufferModified));
*outOffset = offset; *outOffset = offset;
memcpy(data, bufferData.data(), bufferData.size()); memcpy(data, bufferData.data(), bufferData.size());
ANGLE_TRY(dynamicBuffer.flush(contextVk)); ANGLE_TRY(dynamicBuffer->flush(renderer->getDevice()));
return vk::NoError(); return vk::NoError();
} }
...@@ -754,7 +754,7 @@ vk::Error ProgramVk::updateUniforms(ContextVk *contextVk) ...@@ -754,7 +754,7 @@ vk::Error ProgramVk::updateUniforms(ContextVk *contextVk)
if (uniformBlock.uniformsDirty) if (uniformBlock.uniformsDirty)
{ {
bool bufferModified = false; bool bufferModified = false;
ANGLE_TRY(SyncDefaultUniformBlock(contextVk, uniformBlock.storage, ANGLE_TRY(SyncDefaultUniformBlock(contextVk->getRenderer(), &uniformBlock.storage,
uniformBlock.uniformData, uniformBlock.uniformData,
&mUniformBlocksOffsets[index], &bufferModified)); &mUniformBlocksOffsets[index], &bufferModified));
uniformBlock.uniformsDirty = false; uniformBlock.uniformsDirty = false;
......
...@@ -15,17 +15,29 @@ ...@@ -15,17 +15,29 @@
#include "libANGLE/renderer/vulkan/BufferVk.h" #include "libANGLE/renderer/vulkan/BufferVk.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h" #include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace rx namespace rx
{ {
namespace
{
constexpr size_t kDynamicVertexDataSize = 1024 * 1024;
constexpr size_t kDynamicIndexDataSize = 1024 * 8;
} // anonymous namespace
VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state) VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state)
: VertexArrayImpl(state), : VertexArrayImpl(state),
mCurrentArrayBufferHandles{}, mCurrentArrayBufferHandles{},
mCurrentArrayBufferOffsets{}, mCurrentArrayBufferOffsets{},
mCurrentArrayBufferResources{}, mCurrentArrayBufferResources{},
mCurrentElementArrayBufferResource(nullptr) mCurrentElementArrayBufferHandle(VK_NULL_HANDLE),
mCurrentElementArrayBufferOffset(0),
mCurrentElementArrayBufferResource(nullptr),
mDynamicVertexData(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, kDynamicVertexDataSize),
mDynamicIndexData(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, kDynamicIndexDataSize),
mVertexBuffersDirty(false),
mIndexBufferDirty(false)
{ {
mCurrentArrayBufferHandles.fill(VK_NULL_HANDLE); mCurrentArrayBufferHandles.fill(VK_NULL_HANDLE);
mCurrentArrayBufferOffsets.fill(0); mCurrentArrayBufferOffsets.fill(0);
...@@ -33,6 +45,9 @@ VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state) ...@@ -33,6 +45,9 @@ VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state)
mPackedInputBindings.fill({0, 0}); mPackedInputBindings.fill({0, 0});
mPackedInputAttributes.fill({0, 0, 0}); mPackedInputAttributes.fill({0, 0, 0});
mDynamicVertexData.init(1);
mDynamicIndexData.init(1);
} }
VertexArrayVk::~VertexArrayVk() VertexArrayVk::~VertexArrayVk()
...@@ -41,29 +56,27 @@ VertexArrayVk::~VertexArrayVk() ...@@ -41,29 +56,27 @@ VertexArrayVk::~VertexArrayVk()
void VertexArrayVk::destroy(const gl::Context *context) void VertexArrayVk::destroy(const gl::Context *context)
{ {
} VkDevice device = vk::GetImpl(context)->getRenderer()->getDevice();
gl::AttributesMask VertexArrayVk::getAttribsToStream(const gl::Context *context) const mDynamicVertexData.destroy(device);
{ mDynamicIndexData.destroy(device);
const gl::Program *programGL = context->getGLState().getProgram(); mLineLoopHandler.destroy(device);
return mClientMemoryAttribs & programGL->getActiveAttribLocationsMask();
} }
gl::Error VertexArrayVk::streamVertexData(const gl::Context *context, gl::Error VertexArrayVk::streamVertexData(RendererVk *renderer,
DynamicBuffer *dynamicBuffer, const gl::AttributesMask &attribsToStream,
const gl::DrawCallParams &drawCallParams) const gl::DrawCallParams &drawCallParams)
{ {
ContextVk *contextVk = vk::GetImpl(context); ASSERT(!attribsToStream.none());
const auto &attribs = mState.getVertexAttributes(); const auto &attribs = mState.getVertexAttributes();
const auto &bindings = mState.getVertexBindings(); const auto &bindings = mState.getVertexBindings();
ANGLE_TRY(drawCallParams.ensureIndexRangeResolved(context));
const size_t lastVertex = drawCallParams.firstVertex() + drawCallParams.vertexCount(); const size_t lastVertex = drawCallParams.firstVertex() + drawCallParams.vertexCount();
// TODO(fjhenigman): When we have a bunch of interleaved attributes, they end up // TODO(fjhenigman): When we have a bunch of interleaved attributes, they end up
// un-interleaved, wasting space and copying time. Consider improving on that. // un-interleaved, wasting space and copying time. Consider improving on that.
for (auto attribIndex : getAttribsToStream(context)) for (auto attribIndex : attribsToStream)
{ {
const gl::VertexAttribute &attrib = attribs[attribIndex]; const gl::VertexAttribute &attrib = attribs[attribIndex];
const gl::VertexBinding &binding = bindings[attrib.bindingIndex]; const gl::VertexBinding &binding = bindings[attrib.bindingIndex];
...@@ -86,14 +99,48 @@ gl::Error VertexArrayVk::streamVertexData(const gl::Context *context, ...@@ -86,14 +99,48 @@ gl::Error VertexArrayVk::streamVertexData(const gl::Context *context,
lastVertex * binding.getStride() + gl::ComputeVertexAttributeTypeSize(attrib); lastVertex * binding.getStride() + gl::ComputeVertexAttributeTypeSize(attrib);
uint8_t *dst = nullptr; uint8_t *dst = nullptr;
uint32_t offset = 0; uint32_t offset = 0;
ANGLE_TRY(dynamicBuffer->allocate( ANGLE_TRY(mDynamicVertexData.allocate(
contextVk, lastByte, &dst, &mCurrentArrayBufferHandles[attribIndex], &offset, nullptr)); renderer, lastByte, &dst, &mCurrentArrayBufferHandles[attribIndex], &offset, nullptr));
mCurrentArrayBufferOffsets[attribIndex] = static_cast<VkDeviceSize>(offset); mCurrentArrayBufferOffsets[attribIndex] = static_cast<VkDeviceSize>(offset);
memcpy(dst + firstByte, static_cast<const uint8_t *>(attrib.pointer) + firstByte, memcpy(dst + firstByte, static_cast<const uint8_t *>(attrib.pointer) + firstByte,
lastByte - firstByte); lastByte - firstByte);
} }
ANGLE_TRY(dynamicBuffer->flush(contextVk)); ANGLE_TRY(mDynamicVertexData.flush(renderer->getDevice()));
return gl::NoError();
}
gl::Error VertexArrayVk::streamIndexData(RendererVk *renderer,
const gl::DrawCallParams &drawCallParams)
{
ASSERT(!mState.getElementArrayBuffer().get());
uint32_t offset = 0;
const GLsizei amount = sizeof(GLushort) * drawCallParams.indexCount();
GLubyte *dst = nullptr;
ANGLE_TRY(mDynamicIndexData.allocate(renderer, amount, &dst, &mCurrentElementArrayBufferHandle,
&offset, nullptr));
if (drawCallParams.type() == GL_UNSIGNED_BYTE)
{
// Unsigned bytes don't have direct support in Vulkan so we have to expand the
// memory to a GLushort.
const GLubyte *in = static_cast<const GLubyte *>(drawCallParams.indices());
GLushort *expandedDst = reinterpret_cast<GLushort *>(dst);
for (GLsizei index = 0; index < drawCallParams.indexCount(); index++)
{
expandedDst[index] = static_cast<GLushort>(in[index]);
}
}
else
{
memcpy(dst, drawCallParams.indices(), amount);
}
ANGLE_TRY(mDynamicIndexData.flush(renderer->getDevice()));
mCurrentElementArrayBufferOffset = offset;
return gl::NoError(); return gl::NoError();
} }
...@@ -104,9 +151,10 @@ gl::Error VertexArrayVk::syncState(const gl::Context *context, ...@@ -104,9 +151,10 @@ gl::Error VertexArrayVk::syncState(const gl::Context *context,
{ {
ASSERT(dirtyBits.any()); ASSERT(dirtyBits.any());
bool invalidatePipeline = false;
// Invalidate current pipeline. // Invalidate current pipeline.
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
contextVk->onVertexArrayChange();
// Rebuild current attribute buffers cache. This will fail horribly if the buffer changes. // Rebuild current attribute buffers cache. This will fail horribly if the buffer changes.
// TODO(jmadill): Handle buffer storage changes. // TODO(jmadill): Handle buffer storage changes.
...@@ -122,16 +170,24 @@ gl::Error VertexArrayVk::syncState(const gl::Context *context, ...@@ -122,16 +170,24 @@ gl::Error VertexArrayVk::syncState(const gl::Context *context,
gl::Buffer *bufferGL = mState.getElementArrayBuffer().get(); gl::Buffer *bufferGL = mState.getElementArrayBuffer().get();
if (bufferGL) if (bufferGL)
{ {
mCurrentElementArrayBufferResource = vk::GetImpl(bufferGL); BufferVk *bufferVk = vk::GetImpl(bufferGL);
mCurrentElementArrayBufferResource = bufferVk;
mCurrentElementArrayBufferHandle = bufferVk->getVkBuffer().getHandle();
mCurrentElementArrayBufferOffset = 0;
} }
else else
{ {
mCurrentElementArrayBufferResource = nullptr; mCurrentElementArrayBufferResource = nullptr;
mCurrentElementArrayBufferHandle = VK_NULL_HANDLE;
mCurrentElementArrayBufferOffset = 0;
} }
mIndexBufferDirty = true;
break; break;
} }
case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA: case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
mLineLoopBufferFirstIndex.reset();
mLineLoopBufferLastIndex.reset();
break; break;
default: default:
...@@ -170,11 +226,19 @@ gl::Error VertexArrayVk::syncState(const gl::Context *context, ...@@ -170,11 +226,19 @@ gl::Error VertexArrayVk::syncState(const gl::Context *context,
mClientMemoryAttribs.reset(attribIndex); mClientMemoryAttribs.reset(attribIndex);
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
invalidatePipeline = true;
break; break;
} }
} }
} }
if (invalidatePipeline)
{
mVertexBuffersDirty = true;
contextVk->invalidateCurrentPipeline();
}
return gl::NoError(); return gl::NoError();
} }
...@@ -188,30 +252,25 @@ const gl::AttribArray<VkDeviceSize> &VertexArrayVk::getCurrentArrayBufferOffsets ...@@ -188,30 +252,25 @@ const gl::AttribArray<VkDeviceSize> &VertexArrayVk::getCurrentArrayBufferOffsets
return mCurrentArrayBufferOffsets; return mCurrentArrayBufferOffsets;
} }
void VertexArrayVk::updateDrawDependencies(vk::CommandGraphNode *readNode, void VertexArrayVk::updateArrayBufferReadDependencies(vk::CommandGraphNode *drawNode,
const gl::AttributesMask &activeAttribsMask, const gl::AttributesMask &activeAttribsMask,
ResourceVk *elementArrayBufferOverride, Serial serial)
Serial serial,
bool isDrawElements)
{ {
// Handle the bound array buffers. // Handle the bound array buffers.
for (auto attribIndex : activeAttribsMask) for (size_t attribIndex : activeAttribsMask)
{ {
if (mCurrentArrayBufferResources[attribIndex]) if (mCurrentArrayBufferResources[attribIndex])
mCurrentArrayBufferResources[attribIndex]->onReadResource(readNode, serial); mCurrentArrayBufferResources[attribIndex]->onReadResource(drawNode, serial);
} }
}
void VertexArrayVk::updateElementArrayBufferReadDependency(vk::CommandGraphNode *drawNode,
Serial serial)
{
// Handle the bound element array buffer. // Handle the bound element array buffer.
if (isDrawElements) if (mCurrentElementArrayBufferResource)
{
if (elementArrayBufferOverride != nullptr)
{ {
elementArrayBufferOverride->onReadResource(readNode, serial); mCurrentElementArrayBufferResource->onReadResource(drawNode, serial);
}
else if (mCurrentElementArrayBufferResource != nullptr)
{
mCurrentElementArrayBufferResource->onReadResource(readNode, serial);
}
} }
} }
...@@ -271,4 +330,155 @@ void VertexArrayVk::updatePackedInputInfo(uint32_t attribIndex, ...@@ -271,4 +330,155 @@ void VertexArrayVk::updatePackedInputInfo(uint32_t attribIndex,
attribDesc.offset = static_cast<uint32_t>(ComputeVertexAttributeOffset(attrib, binding)); attribDesc.offset = static_cast<uint32_t>(ComputeVertexAttributeOffset(attrib, binding));
} }
gl::Error VertexArrayVk::drawArrays(const gl::Context *context,
RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
vk::CommandGraphNode *drawNode,
bool newCommandBuffer)
{
vk::CommandBuffer *commandBuffer = drawNode->getInsideRenderPassCommands();
ASSERT(commandBuffer->valid());
ANGLE_TRY(onDraw(context, renderer, drawCallParams, drawNode, newCommandBuffer));
if (drawCallParams.mode() != GL_LINE_LOOP)
{
commandBuffer->draw(drawCallParams.vertexCount(), 1, drawCallParams.firstVertex(), 0);
return gl::NoError();
}
// Handle GL_LINE_LOOP drawArrays.
int lastVertex = drawCallParams.firstVertex() + drawCallParams.vertexCount();
if (!mLineLoopBufferFirstIndex.valid() || !mLineLoopBufferLastIndex.valid() ||
mLineLoopBufferFirstIndex != drawCallParams.firstVertex() ||
mLineLoopBufferLastIndex != lastVertex)
{
ANGLE_TRY(mLineLoopHandler.createIndexBuffer(renderer, drawCallParams,
&mCurrentElementArrayBufferHandle,
&mCurrentElementArrayBufferOffset));
mLineLoopBufferFirstIndex = drawCallParams.firstVertex();
mLineLoopBufferLastIndex = lastVertex;
}
commandBuffer->bindIndexBuffer(mCurrentElementArrayBufferHandle,
mCurrentElementArrayBufferOffset, VK_INDEX_TYPE_UINT32);
vk::LineLoopHandler::Draw(drawCallParams.vertexCount(), commandBuffer);
return gl::NoError();
}
gl::Error VertexArrayVk::drawElements(const gl::Context *context,
RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
vk::CommandGraphNode *drawNode,
bool newCommandBuffer)
{
vk::CommandBuffer *commandBuffer = drawNode->getInsideRenderPassCommands();
ASSERT(commandBuffer->valid());
if (drawCallParams.mode() != GL_LINE_LOOP)
{
ANGLE_TRY(onIndexedDraw(context, renderer, drawCallParams, drawNode, newCommandBuffer));
commandBuffer->drawIndexed(drawCallParams.indexCount(), 1, 0, 0, 0);
return gl::NoError();
}
// Handle GL_LINE_LOOP drawElements.
gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
if (!elementArrayBuffer)
{
UNIMPLEMENTED();
return gl::InternalError() << "Line loop indices in client memory not supported";
}
BufferVk *elementArrayBufferVk = vk::GetImpl(elementArrayBuffer);
VkIndexType indexType = gl_vk::GetIndexType(drawCallParams.type());
ANGLE_TRY(mLineLoopHandler.createIndexBufferFromElementArrayBuffer(
renderer, elementArrayBufferVk, indexType, drawCallParams.indexCount(),
&mCurrentElementArrayBufferHandle, &mCurrentElementArrayBufferOffset));
ANGLE_TRY(onIndexedDraw(context, renderer, drawCallParams, drawNode, newCommandBuffer));
vk::LineLoopHandler::Draw(drawCallParams.indexCount(), commandBuffer);
return gl::NoError();
}
gl::Error VertexArrayVk::onDraw(const gl::Context *context,
RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
vk::CommandGraphNode *drawNode,
bool newCommandBuffer)
{
const gl::State &state = context->getGLState();
const gl::Program *programGL = state.getProgram();
const gl::AttributesMask &activeAttribs = programGL->getActiveAttribLocationsMask();
uint32_t maxAttrib = programGL->getState().getMaxActiveAttribLocation();
if (mClientMemoryAttribs.any())
{
const gl::AttributesMask &attribsToStream = (mClientMemoryAttribs & activeAttribs);
if (attribsToStream.any())
{
ANGLE_TRY(drawCallParams.ensureIndexRangeResolved(context));
ANGLE_TRY(streamVertexData(renderer, attribsToStream, drawCallParams));
vk::CommandBuffer *commandBuffer = drawNode->getInsideRenderPassCommands();
commandBuffer->bindVertexBuffers(0, maxAttrib, mCurrentArrayBufferHandles.data(),
mCurrentArrayBufferOffsets.data());
}
}
else if (mVertexBuffersDirty || newCommandBuffer)
{
vk::CommandBuffer *commandBuffer = drawNode->getInsideRenderPassCommands();
commandBuffer->bindVertexBuffers(0, maxAttrib, mCurrentArrayBufferHandles.data(),
mCurrentArrayBufferOffsets.data());
updateArrayBufferReadDependencies(drawNode, activeAttribs,
renderer->getCurrentQueueSerial());
mVertexBuffersDirty = false;
}
return gl::NoError();
}
gl::Error VertexArrayVk::onIndexedDraw(const gl::Context *context,
RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
vk::CommandGraphNode *drawNode,
bool newCommandBuffer)
{
ANGLE_TRY(onDraw(context, renderer, drawCallParams, drawNode, newCommandBuffer));
if (!mState.getElementArrayBuffer().get())
{
ANGLE_TRY(drawCallParams.ensureIndexRangeResolved(context));
ANGLE_TRY(streamIndexData(renderer, drawCallParams));
vk::CommandBuffer *commandBuffer = drawNode->getInsideRenderPassCommands();
commandBuffer->bindIndexBuffer(mCurrentElementArrayBufferHandle,
mCurrentElementArrayBufferOffset,
gl_vk::GetIndexType(drawCallParams.type()));
}
else if (mIndexBufferDirty || newCommandBuffer)
{
if (drawCallParams.type() == GL_UNSIGNED_BYTE)
{
// TODO(fjhenigman): Index format translation.
UNIMPLEMENTED();
return gl::InternalError()
<< "Unsigned byte translation is not implemented for indices in a buffer object";
}
vk::CommandBuffer *commandBuffer = drawNode->getInsideRenderPassCommands();
commandBuffer->bindIndexBuffer(mCurrentElementArrayBufferHandle,
mCurrentElementArrayBufferOffset,
gl_vk::GetIndexType(drawCallParams.type()));
updateElementArrayBufferReadDependency(drawNode, renderer->getCurrentQueueSerial());
mIndexBufferDirty = false;
}
return gl::NoError();
}
} // namespace rx } // namespace rx
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#define LIBANGLE_RENDERER_VULKAN_VERTEXARRAYVK_H_ #define LIBANGLE_RENDERER_VULKAN_VERTEXARRAYVK_H_
#include "libANGLE/renderer/VertexArrayImpl.h" #include "libANGLE/renderer/VertexArrayImpl.h"
#include "libANGLE/renderer/vulkan/DynamicBuffer.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h" #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
namespace gl namespace gl
...@@ -31,10 +32,6 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -31,10 +32,6 @@ class VertexArrayVk : public VertexArrayImpl
void destroy(const gl::Context *context) override; void destroy(const gl::Context *context) override;
gl::Error streamVertexData(const gl::Context *context,
DynamicBuffer *dynamicBuffer,
const gl::DrawCallParams &drawCallParams);
gl::Error syncState(const gl::Context *context, gl::Error syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, const gl::VertexArray::DirtyAttribBitsArray &attribBits,
...@@ -43,14 +40,20 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -43,14 +40,20 @@ class VertexArrayVk : public VertexArrayImpl
const gl::AttribArray<VkBuffer> &getCurrentArrayBufferHandles() const; const gl::AttribArray<VkBuffer> &getCurrentArrayBufferHandles() const;
const gl::AttribArray<VkDeviceSize> &getCurrentArrayBufferOffsets() const; const gl::AttribArray<VkDeviceSize> &getCurrentArrayBufferOffsets() const;
void updateDrawDependencies(vk::CommandGraphNode *readNode,
const gl::AttributesMask &activeAttribsMask,
ResourceVk *elementArrayBufferOverride,
Serial serial,
bool isDrawElements);
void getPackedInputDescriptions(vk::PipelineDesc *pipelineDesc); void getPackedInputDescriptions(vk::PipelineDesc *pipelineDesc);
// Draw call handling.
gl::Error drawArrays(const gl::Context *context,
RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
vk::CommandGraphNode *drawNode,
bool newCommandBuffer);
gl::Error drawElements(const gl::Context *context,
RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
vk::CommandGraphNode *drawNode,
bool newCommandBuffer);
private: private:
// This will update any dirty packed input descriptions, regardless if they're used by the // This will update any dirty packed input descriptions, regardless if they're used by the
// active program. This could lead to slight inefficiencies when the app would repeatedly // active program. This could lead to slight inefficiencies when the app would repeatedly
...@@ -62,11 +65,34 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -62,11 +65,34 @@ class VertexArrayVk : public VertexArrayImpl
const gl::VertexBinding &binding, const gl::VertexBinding &binding,
const gl::VertexAttribute &attrib); const gl::VertexAttribute &attrib);
gl::AttributesMask getAttribsToStream(const gl::Context *context) const; void updateArrayBufferReadDependencies(vk::CommandGraphNode *drawNode,
const gl::AttributesMask &activeAttribsMask,
Serial serial);
void updateElementArrayBufferReadDependency(vk::CommandGraphNode *drawNode, Serial serial);
gl::Error streamVertexData(RendererVk *renderer,
const gl::AttributesMask &attribsToStream,
const gl::DrawCallParams &drawCallParams);
gl::Error streamIndexData(RendererVk *renderer, const gl::DrawCallParams &drawCallParams);
gl::Error onDraw(const gl::Context *context,
RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
vk::CommandGraphNode *drawNode,
bool newCommandBuffer);
gl::Error onIndexedDraw(const gl::Context *context,
RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
vk::CommandGraphNode *drawNode,
bool newCommandBuffer);
gl::AttribArray<VkBuffer> mCurrentArrayBufferHandles; gl::AttribArray<VkBuffer> mCurrentArrayBufferHandles;
gl::AttribArray<VkDeviceSize> mCurrentArrayBufferOffsets; gl::AttribArray<VkDeviceSize> mCurrentArrayBufferOffsets;
gl::AttribArray<ResourceVk *> mCurrentArrayBufferResources; gl::AttribArray<ResourceVk *> mCurrentArrayBufferResources;
VkBuffer mCurrentElementArrayBufferHandle;
VkDeviceSize mCurrentElementArrayBufferOffset;
ResourceVk *mCurrentElementArrayBufferResource; ResourceVk *mCurrentElementArrayBufferResource;
// Keep a cache of binding and attribute descriptions for easy pipeline updates. // Keep a cache of binding and attribute descriptions for easy pipeline updates.
...@@ -78,6 +104,17 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -78,6 +104,17 @@ class VertexArrayVk : public VertexArrayImpl
// Which attributes need to be copied from client memory. // Which attributes need to be copied from client memory.
// TODO(jmadill): Move this to VertexArrayState. http://anglebug.com/2389 // TODO(jmadill): Move this to VertexArrayState. http://anglebug.com/2389
gl::AttributesMask mClientMemoryAttribs; gl::AttributesMask mClientMemoryAttribs;
DynamicBuffer mDynamicVertexData;
DynamicBuffer mDynamicIndexData;
vk::LineLoopHandler mLineLoopHandler;
Optional<int> mLineLoopBufferFirstIndex;
Optional<int> mLineLoopBufferLastIndex;
// Cache variable for determining whether or not to store new dependencies in the node.
bool mVertexBuffersDirty;
bool mIndexBufferDirty;
}; };
} // namespace rx } // namespace rx
......
...@@ -1179,93 +1179,84 @@ LineLoopHandler::LineLoopHandler() ...@@ -1179,93 +1179,84 @@ LineLoopHandler::LineLoopHandler()
: mObserverBinding(this, 0u), : mObserverBinding(this, 0u),
mDynamicLineLoopIndicesData( mDynamicLineLoopIndicesData(
new DynamicBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, new DynamicBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
kLineLoopDynamicBufferMinSize)), kLineLoopDynamicBufferMinSize))
mLineLoopIndexBuffer(VK_NULL_HANDLE),
mLineLoopIndexBufferOffset(VK_NULL_HANDLE)
{ {
mDynamicLineLoopIndicesData->init(1); mDynamicLineLoopIndicesData->init(1);
} }
LineLoopHandler::~LineLoopHandler() = default; LineLoopHandler::~LineLoopHandler() = default;
void LineLoopHandler::bindIndexBuffer(VkIndexType indexType, vk::CommandBuffer **commandBuffer) gl::Error LineLoopHandler::createIndexBuffer(RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
VkBuffer *bufferHandleOut,
VkDeviceSize *offsetOut)
{ {
(*commandBuffer)->bindIndexBuffer(mLineLoopIndexBuffer, mLineLoopIndexBufferOffset, indexType);
}
gl::Error LineLoopHandler::createIndexBuffer(ContextVk *contextVk, int firstVertex, int count)
{
int lastVertex = firstVertex + count;
if (mLineLoopIndexBuffer == VK_NULL_HANDLE || !mLineLoopBufferFirstIndex.valid() ||
!mLineLoopBufferLastIndex.valid() || mLineLoopBufferFirstIndex != firstVertex ||
mLineLoopBufferLastIndex != lastVertex)
{
uint32_t *indices = nullptr; uint32_t *indices = nullptr;
size_t allocateBytes = sizeof(uint32_t) * (count + 1); size_t allocateBytes = sizeof(uint32_t) * (drawCallParams.vertexCount() + 1);
ANGLE_TRY(mDynamicLineLoopIndicesData->allocate( uint32_t offset = 0;
contextVk, allocateBytes, reinterpret_cast<uint8_t **>(&indices), &mLineLoopIndexBuffer, ANGLE_TRY(mDynamicLineLoopIndicesData->allocate(renderer, allocateBytes,
&mLineLoopIndexBufferOffset, nullptr)); reinterpret_cast<uint8_t **>(&indices),
bufferHandleOut, &offset, nullptr));
auto unsignedFirstVertex = static_cast<uint32_t>(firstVertex); *offsetOut = static_cast<VkDeviceSize>(offset);
for (auto vertexIndex = unsignedFirstVertex; vertexIndex < (count + unsignedFirstVertex);
vertexIndex++) uint32_t unsignedFirstVertex = static_cast<uint32_t>(drawCallParams.firstVertex());
uint32_t vertexCount = (drawCallParams.vertexCount() + unsignedFirstVertex);
for (uint32_t vertexIndex = unsignedFirstVertex; vertexIndex < vertexCount; vertexIndex++)
{ {
*indices++ = vertexIndex; *indices++ = vertexIndex;
} }
*indices = unsignedFirstVertex; *indices = unsignedFirstVertex;
// Since we are not using the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT flag when creating the // Since we are not using the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT flag when creating the
// device memory in the DynamicBuffer, we always need to make sure we flush it after // device memory in the StreamingBuffer, we always need to make sure we flush it after
// writing. // writing.
ANGLE_TRY(mDynamicLineLoopIndicesData->flush(contextVk)); ANGLE_TRY(mDynamicLineLoopIndicesData->flush(renderer->getDevice()));
mLineLoopBufferFirstIndex = firstVertex;
mLineLoopBufferLastIndex = lastVertex;
}
return gl::NoError(); return gl::NoError();
} }
gl::Error LineLoopHandler::createIndexBufferFromElementArrayBuffer(ContextVk *contextVk, gl::Error LineLoopHandler::createIndexBufferFromElementArrayBuffer(RendererVk *renderer,
BufferVk *bufferVk, BufferVk *elementArrayBufferVk,
VkIndexType indexType, VkIndexType indexType,
int count) int indexCount,
VkBuffer *bufferHandleOut,
VkDeviceSize *bufferOffsetOut)
{ {
ASSERT(indexType == VK_INDEX_TYPE_UINT16 || indexType == VK_INDEX_TYPE_UINT32); ASSERT(indexType == VK_INDEX_TYPE_UINT16 || indexType == VK_INDEX_TYPE_UINT32);
if (bufferVk == mObserverBinding.getSubject() && mLineLoopIndexBuffer != VK_NULL_HANDLE) if (elementArrayBufferVk == mObserverBinding.getSubject())
{ {
return gl::NoError(); return gl::NoError();
} }
// We want to know if the bufferVk changes at any point in time, because if it does we need to // We want to know if the bufferVk changes at any point in time, because if it does we need to
// recopy our data on the next call. // recopy our data on the next call.
mObserverBinding.bind(bufferVk); mObserverBinding.bind(elementArrayBufferVk);
uint32_t *indices = nullptr; uint32_t *indices = nullptr;
uint32_t offset = 0;
auto unitSize = (indexType == VK_INDEX_TYPE_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t)); auto unitSize = (indexType == VK_INDEX_TYPE_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t));
size_t allocateBytes = unitSize * (count + 1); size_t allocateBytes = unitSize * (indexCount + 1);
ANGLE_TRY(mDynamicLineLoopIndicesData->allocate( ANGLE_TRY(mDynamicLineLoopIndicesData->allocate(renderer, allocateBytes,
contextVk, allocateBytes, reinterpret_cast<uint8_t **>(&indices), &mLineLoopIndexBuffer, reinterpret_cast<uint8_t **>(&indices),
&mLineLoopIndexBufferOffset, nullptr)); bufferHandleOut, &offset, nullptr));
*bufferOffsetOut = static_cast<VkDeviceSize>(offset);
VkBufferCopy copy1 = {0, mLineLoopIndexBufferOffset,
static_cast<VkDeviceSize>(count) * unitSize}; VkBufferCopy copy1 = {0, offset, static_cast<VkDeviceSize>(indexCount) * unitSize};
VkBufferCopy copy2 = { VkBufferCopy copy2 = {0, offset + static_cast<VkDeviceSize>(indexCount) * unitSize, unitSize};
0, mLineLoopIndexBufferOffset + static_cast<VkDeviceSize>(count) * unitSize, unitSize};
std::array<VkBufferCopy, 2> copies = {{copy1, copy2}}; std::array<VkBufferCopy, 2> copies = {{copy1, copy2}};
vk::CommandBuffer *commandBuffer; vk::CommandBuffer *commandBuffer;
mDynamicLineLoopIndicesData->beginWriteResource(contextVk->getRenderer(), &commandBuffer); mDynamicLineLoopIndicesData->beginWriteResource(renderer, &commandBuffer);
Serial currentSerial = contextVk->getRenderer()->getCurrentQueueSerial(); Serial currentSerial = renderer->getCurrentQueueSerial();
bufferVk->onReadResource(mDynamicLineLoopIndicesData->getCurrentWritingNode(currentSerial), elementArrayBufferVk->onReadResource(
currentSerial); mDynamicLineLoopIndicesData->getCurrentWritingNode(currentSerial), currentSerial);
commandBuffer->copyBuffer(bufferVk->getVkBuffer().getHandle(), mLineLoopIndexBuffer, 2, commandBuffer->copyBuffer(elementArrayBufferVk->getVkBuffer().getHandle(), *bufferHandleOut, 2,
copies.data()); copies.data());
ANGLE_TRY(mDynamicLineLoopIndicesData->flush(contextVk)); ANGLE_TRY(mDynamicLineLoopIndicesData->flush(renderer->getDevice()));
return gl::NoError(); return gl::NoError();
} }
...@@ -1275,13 +1266,11 @@ void LineLoopHandler::destroy(VkDevice device) ...@@ -1275,13 +1266,11 @@ void LineLoopHandler::destroy(VkDevice device)
mDynamicLineLoopIndicesData->destroy(device); mDynamicLineLoopIndicesData->destroy(device);
} }
gl::Error LineLoopHandler::draw(int count, CommandBuffer *commandBuffer) // static
void LineLoopHandler::Draw(int count, CommandBuffer *commandBuffer)
{ {
// Our first index is always 0 because that's how we set it up in the // Our first index is always 0 because that's how we set it up in createIndexBuffer*.
// bindLineLoopIndexBuffer.
commandBuffer->drawIndexed(count + 1, 1, 0, 0, 0); commandBuffer->drawIndexed(count + 1, 1, 0, 0, 0);
return gl::NoError();
} }
ResourceVk *LineLoopHandler::getLineLoopBufferResource() ResourceVk *LineLoopHandler::getLineLoopBufferResource()
...@@ -1296,7 +1285,7 @@ void LineLoopHandler::onSubjectStateChange(const gl::Context *context, ...@@ -1296,7 +1285,7 @@ void LineLoopHandler::onSubjectStateChange(const gl::Context *context,
// Indicate we want to recopy on next draw since something changed in the buffer. // Indicate we want to recopy on next draw since something changed in the buffer.
if (message == angle::SubjectMessage::CONTENTS_CHANGED) if (message == angle::SubjectMessage::CONTENTS_CHANGED)
{ {
mLineLoopIndexBuffer = VK_NULL_HANDLE; mObserverBinding.reset();
} }
} }
...@@ -1768,6 +1757,21 @@ VkComponentSwizzle GetSwizzle(const GLenum swizzle) ...@@ -1768,6 +1757,21 @@ VkComponentSwizzle GetSwizzle(const GLenum swizzle)
return VK_COMPONENT_SWIZZLE_IDENTITY; return VK_COMPONENT_SWIZZLE_IDENTITY;
} }
} }
VkIndexType GetIndexType(GLenum elementType)
{
switch (elementType)
{
case GL_UNSIGNED_BYTE:
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;
}
}
} // namespace gl_vk } // namespace gl_vk
ResourceVk::ResourceVk() : mCurrentWritingNode(nullptr) ResourceVk::ResourceVk() : mCurrentWritingNode(nullptr)
......
...@@ -38,6 +38,7 @@ class Display; ...@@ -38,6 +38,7 @@ class Display;
namespace gl namespace gl
{ {
struct Box; struct Box;
class DrawCallParams;
struct Extents; struct Extents;
struct RasterizerState; struct RasterizerState;
struct Rectangle; struct Rectangle;
...@@ -641,27 +642,32 @@ Error AllocateImageMemory(RendererVk *renderer, ...@@ -641,27 +642,32 @@ 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. // This class' responsibility is to create index buffers needed to support line loops in Vulkan.
// In the setup phase of drawing, the bindLineLoopIndexBuffer method should be called with the // In the setup phase of drawing, the createIndexBuffer method should be called with the
// first/last vertex and the current commandBuffer. If the user wants to draw a loop between [v1, // current draw call parameters. If an element array buffer is bound for an indexed draw, use
// v2, v3], we will create an indexed buffer with these indexes: [0, 1, 2, 3, 0] to emulate the // createIndexBufferFromElementArrayBuffer.
// loop. //
// 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, angle::ObserverInterface class LineLoopHandler final : angle::NonCopyable, angle::ObserverInterface
{ {
public: public:
LineLoopHandler(); LineLoopHandler();
~LineLoopHandler(); ~LineLoopHandler();
void bindIndexBuffer(VkIndexType indexType, CommandBuffer **commandBuffer); gl::Error createIndexBuffer(RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
gl::Error createIndexBuffer(ContextVk *contextVk, int firstVertex, int count); VkBuffer *bufferHandleOut,
gl::Error createIndexBufferFromElementArrayBuffer(ContextVk *contextVk, VkDeviceSize *offsetOut);
BufferVk *bufferVk, gl::Error createIndexBufferFromElementArrayBuffer(RendererVk *renderer,
BufferVk *elementArrayBufferVk,
VkIndexType indexType, VkIndexType indexType,
int count); int indexCount,
VkBuffer *bufferHandleOut,
VkDeviceSize *bufferOffsetOut);
void destroy(VkDevice device); void destroy(VkDevice device);
gl::Error draw(int count, CommandBuffer *commandBuffer); static void Draw(int count, CommandBuffer *commandBuffer);
ResourceVk *getLineLoopBufferResource(); ResourceVk *getLineLoopBufferResource();
...@@ -673,10 +679,6 @@ class LineLoopHandler final : angle::NonCopyable, angle::ObserverInterface ...@@ -673,10 +679,6 @@ class LineLoopHandler final : angle::NonCopyable, angle::ObserverInterface
private: private:
angle::ObserverBinding mObserverBinding; angle::ObserverBinding mObserverBinding;
std::unique_ptr<DynamicBuffer> mDynamicLineLoopIndicesData; std::unique_ptr<DynamicBuffer> mDynamicLineLoopIndicesData;
VkBuffer mLineLoopIndexBuffer;
uint32_t mLineLoopIndexBufferOffset;
Optional<int> mLineLoopBufferFirstIndex;
Optional<int> mLineLoopBufferLastIndex;
}; };
class ImageHelper final : angle::NonCopyable class ImageHelper final : angle::NonCopyable
...@@ -771,6 +773,7 @@ VkCullModeFlags GetCullMode(const gl::RasterizerState &rasterState); ...@@ -771,6 +773,7 @@ VkCullModeFlags GetCullMode(const gl::RasterizerState &rasterState);
VkFrontFace GetFrontFace(GLenum frontFace); VkFrontFace GetFrontFace(GLenum frontFace);
VkSampleCountFlagBits GetSamples(GLint sampleCount); VkSampleCountFlagBits GetSamples(GLint sampleCount);
VkComponentSwizzle GetSwizzle(const GLenum swizzle); VkComponentSwizzle GetSwizzle(const GLenum swizzle);
VkIndexType GetIndexType(GLenum elementType);
} // namespace gl_vk } // namespace gl_vk
// This is a helper class for back-end objects used in Vk command buffers. It records a serial // This is a helper class for back-end objects used in Vk command buffers. It records a serial
......
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