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
......@@ -155,7 +155,6 @@ class ContextVk : public ContextImpl
RendererVk *getRenderer() { return mRenderer; }
void invalidateCurrentPipeline();
void onVertexArrayChange();
DynamicDescriptorPool *getDynamicDescriptorPool();
......@@ -167,8 +166,8 @@ class ContextVk : public ContextImpl
gl::Error initPipeline(const gl::Context *context);
gl::Error setupDraw(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
ResourceVk *elementArrayBufferOverride,
vk::CommandBuffer **commandBufferOut);
vk::CommandGraphNode **drawNodeOut,
bool *newCommandBufferOut);
RendererVk *mRenderer;
vk::PipelineAndSerial *mCurrentPipeline;
......@@ -183,17 +182,12 @@ class ContextVk : public ContextImpl
DynamicDescriptorPool mDynamicDescriptorPool;
// Triggers adding dependencies to the command graph.
bool mVertexArrayDirty;
bool mTexturesDirty;
bool mVertexArrayBindingHasChanged;
// Cached clear value for color and depth/stencil.
VkClearValue mClearColorValue;
VkClearValue mClearDepthStencilValue;
DynamicBuffer mDynamicVertexData;
DynamicBuffer mDynamicIndexData;
vk::LineLoopHandler mLineLoopHandler;
};
} // namespace rx
......
......@@ -44,7 +44,7 @@ bool DynamicBuffer::valid()
return mAlignment > 0;
}
vk::Error DynamicBuffer::allocate(ContextVk *context,
vk::Error DynamicBuffer::allocate(RendererVk *renderer,
size_t sizeInBytes,
uint8_t **ptrOut,
VkBuffer *handleOut,
......@@ -52,11 +52,7 @@ vk::Error DynamicBuffer::allocate(ContextVk *context,
bool *outNewBufferAllocated)
{
ASSERT(valid());
RendererVk *renderer = context->getRenderer();
// TODO(fjhenigman): Update this when we have buffers that need to
// persist longer than one frame.
updateQueueSerial(renderer->getCurrentQueueSerial());
VkDevice device = renderer->getDevice();
size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
......@@ -65,16 +61,15 @@ vk::Error DynamicBuffer::allocate(ContextVk *context,
if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
{
VkDevice device = context->getDevice();
if (mMappedMemory)
{
ANGLE_TRY(flush(context));
ANGLE_TRY(flush(device));
mMemory.unmap(device);
mMappedMemory = nullptr;
}
renderer->releaseResource(*this, &mBuffer);
renderer->releaseResource(*this, &mMemory);
Serial currentSerial = renderer->getCurrentQueueSerial();
renderer->releaseObject(currentSerial, &mBuffer);
renderer->releaseObject(currentSerial, &mMemory);
VkBufferCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
......@@ -121,7 +116,7 @@ vk::Error DynamicBuffer::allocate(ContextVk *context,
return vk::NoError();
}
vk::Error DynamicBuffer::flush(ContextVk *context)
vk::Error DynamicBuffer::flush(VkDevice device)
{
if (mNextWriteOffset > mLastFlushOffset)
{
......@@ -131,7 +126,7 @@ vk::Error DynamicBuffer::flush(ContextVk *context)
range.memory = mMemory.getHandle();
range.offset = mLastFlushOffset;
range.size = mNextWriteOffset - mLastFlushOffset;
ANGLE_VK_TRY(vkFlushMappedMemoryRanges(context->getDevice(), 1, &range));
ANGLE_VK_TRY(vkFlushMappedMemoryRanges(device, 1, &range));
mLastFlushOffset = mNextWriteOffset;
}
......
......@@ -20,16 +20,17 @@ class DynamicBuffer : public ResourceVk
{
public:
DynamicBuffer(VkBufferUsageFlags usage, size_t minSize);
~DynamicBuffer();
void init(size_t alignment);
bool valid();
~DynamicBuffer();
vk::Error allocate(ContextVk *context,
vk::Error allocate(RendererVk *renderer,
size_t sizeInBytes,
uint8_t **ptrOut,
VkBuffer *handleOut,
uint32_t *offsetOut,
bool *outNewBufferAllocated);
vk::Error flush(ContextVk *context);
vk::Error flush(VkDevice device);
void destroy(VkDevice device);
VkBuffer getCurrentBufferHandle() const;
......
......@@ -113,8 +113,8 @@ void ReadFromDefaultUniformBlock(int componentCount,
}
}
vk::Error SyncDefaultUniformBlock(ContextVk *contextVk,
DynamicBuffer &dynamicBuffer,
vk::Error SyncDefaultUniformBlock(RendererVk *renderer,
DynamicBuffer *dynamicBuffer,
const angle::MemoryBuffer &bufferData,
uint32_t *outOffset,
bool *outBufferModified)
......@@ -123,11 +123,11 @@ vk::Error SyncDefaultUniformBlock(ContextVk *contextVk,
uint8_t *data = nullptr;
VkBuffer *outBuffer = nullptr;
uint32_t offset;
ANGLE_TRY(dynamicBuffer.allocate(contextVk, bufferData.size(), &data, outBuffer, &offset,
outBufferModified));
ANGLE_TRY(dynamicBuffer->allocate(renderer, bufferData.size(), &data, outBuffer, &offset,
outBufferModified));
*outOffset = offset;
memcpy(data, bufferData.data(), bufferData.size());
ANGLE_TRY(dynamicBuffer.flush(contextVk));
ANGLE_TRY(dynamicBuffer->flush(renderer->getDevice()));
return vk::NoError();
}
......@@ -754,7 +754,7 @@ vk::Error ProgramVk::updateUniforms(ContextVk *contextVk)
if (uniformBlock.uniformsDirty)
{
bool bufferModified = false;
ANGLE_TRY(SyncDefaultUniformBlock(contextVk, uniformBlock.storage,
ANGLE_TRY(SyncDefaultUniformBlock(contextVk->getRenderer(), &uniformBlock.storage,
uniformBlock.uniformData,
&mUniformBlocksOffsets[index], &bufferModified));
uniformBlock.uniformsDirty = false;
......
......@@ -11,6 +11,7 @@
#define LIBANGLE_RENDERER_VULKAN_VERTEXARRAYVK_H_
#include "libANGLE/renderer/VertexArrayImpl.h"
#include "libANGLE/renderer/vulkan/DynamicBuffer.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
namespace gl
......@@ -31,10 +32,6 @@ class VertexArrayVk : public VertexArrayImpl
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,
const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
......@@ -43,14 +40,20 @@ class VertexArrayVk : public VertexArrayImpl
const gl::AttribArray<VkBuffer> &getCurrentArrayBufferHandles() 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);
// 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:
// 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
......@@ -62,11 +65,34 @@ class VertexArrayVk : public VertexArrayImpl
const gl::VertexBinding &binding,
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<VkDeviceSize> mCurrentArrayBufferOffsets;
gl::AttribArray<ResourceVk *> mCurrentArrayBufferResources;
VkBuffer mCurrentElementArrayBufferHandle;
VkDeviceSize mCurrentElementArrayBufferOffset;
ResourceVk *mCurrentElementArrayBufferResource;
// Keep a cache of binding and attribute descriptions for easy pipeline updates.
......@@ -78,6 +104,17 @@ class VertexArrayVk : public VertexArrayImpl
// Which attributes need to be copied from client memory.
// TODO(jmadill): Move this to VertexArrayState. http://anglebug.com/2389
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
......
......@@ -1179,93 +1179,84 @@ LineLoopHandler::LineLoopHandler()
: mObserverBinding(this, 0u),
mDynamicLineLoopIndicesData(
new DynamicBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
kLineLoopDynamicBufferMinSize)),
mLineLoopIndexBuffer(VK_NULL_HANDLE),
mLineLoopIndexBufferOffset(VK_NULL_HANDLE)
kLineLoopDynamicBufferMinSize))
{
mDynamicLineLoopIndicesData->init(1);
}
LineLoopHandler::~LineLoopHandler() = default;
void LineLoopHandler::bindIndexBuffer(VkIndexType indexType, vk::CommandBuffer **commandBuffer)
{
(*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)
gl::Error LineLoopHandler::createIndexBuffer(RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
VkBuffer *bufferHandleOut,
VkDeviceSize *offsetOut)
{
uint32_t *indices = nullptr;
size_t allocateBytes = sizeof(uint32_t) * (drawCallParams.vertexCount() + 1);
uint32_t offset = 0;
ANGLE_TRY(mDynamicLineLoopIndicesData->allocate(renderer, allocateBytes,
reinterpret_cast<uint8_t **>(&indices),
bufferHandleOut, &offset, nullptr));
*offsetOut = static_cast<VkDeviceSize>(offset);
uint32_t unsignedFirstVertex = static_cast<uint32_t>(drawCallParams.firstVertex());
uint32_t vertexCount = (drawCallParams.vertexCount() + unsignedFirstVertex);
for (uint32_t vertexIndex = unsignedFirstVertex; vertexIndex < vertexCount; vertexIndex++)
{
uint32_t *indices = nullptr;
size_t allocateBytes = sizeof(uint32_t) * (count + 1);
ANGLE_TRY(mDynamicLineLoopIndicesData->allocate(
contextVk, allocateBytes, reinterpret_cast<uint8_t **>(&indices), &mLineLoopIndexBuffer,
&mLineLoopIndexBufferOffset, nullptr));
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 DynamicBuffer, we always need to make sure we flush it after
// writing.
ANGLE_TRY(mDynamicLineLoopIndicesData->flush(contextVk));
mLineLoopBufferFirstIndex = firstVertex;
mLineLoopBufferLastIndex = lastVertex;
*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(mDynamicLineLoopIndicesData->flush(renderer->getDevice()));
return gl::NoError();
}
gl::Error LineLoopHandler::createIndexBufferFromElementArrayBuffer(ContextVk *contextVk,
BufferVk *bufferVk,
gl::Error LineLoopHandler::createIndexBufferFromElementArrayBuffer(RendererVk *renderer,
BufferVk *elementArrayBufferVk,
VkIndexType indexType,
int count)
int indexCount,
VkBuffer *bufferHandleOut,
VkDeviceSize *bufferOffsetOut)
{
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();
}
// 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.
mObserverBinding.bind(bufferVk);
mObserverBinding.bind(elementArrayBufferVk);
uint32_t *indices = nullptr;
uint32_t offset = 0;
auto unitSize = (indexType == VK_INDEX_TYPE_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t));
size_t allocateBytes = unitSize * (count + 1);
ANGLE_TRY(mDynamicLineLoopIndicesData->allocate(
contextVk, allocateBytes, reinterpret_cast<uint8_t **>(&indices), &mLineLoopIndexBuffer,
&mLineLoopIndexBufferOffset, nullptr));
VkBufferCopy copy1 = {0, mLineLoopIndexBufferOffset,
static_cast<VkDeviceSize>(count) * unitSize};
VkBufferCopy copy2 = {
0, mLineLoopIndexBufferOffset + static_cast<VkDeviceSize>(count) * unitSize, unitSize};
size_t allocateBytes = unitSize * (indexCount + 1);
ANGLE_TRY(mDynamicLineLoopIndicesData->allocate(renderer, allocateBytes,
reinterpret_cast<uint8_t **>(&indices),
bufferHandleOut, &offset, nullptr));
*bufferOffsetOut = static_cast<VkDeviceSize>(offset);
VkBufferCopy copy1 = {0, offset, static_cast<VkDeviceSize>(indexCount) * unitSize};
VkBufferCopy copy2 = {0, offset + static_cast<VkDeviceSize>(indexCount) * unitSize, unitSize};
std::array<VkBufferCopy, 2> copies = {{copy1, copy2}};
vk::CommandBuffer *commandBuffer;
mDynamicLineLoopIndicesData->beginWriteResource(contextVk->getRenderer(), &commandBuffer);
mDynamicLineLoopIndicesData->beginWriteResource(renderer, &commandBuffer);
Serial currentSerial = contextVk->getRenderer()->getCurrentQueueSerial();
bufferVk->onReadResource(mDynamicLineLoopIndicesData->getCurrentWritingNode(currentSerial),
currentSerial);
commandBuffer->copyBuffer(bufferVk->getVkBuffer().getHandle(), mLineLoopIndexBuffer, 2,
Serial currentSerial = renderer->getCurrentQueueSerial();
elementArrayBufferVk->onReadResource(
mDynamicLineLoopIndicesData->getCurrentWritingNode(currentSerial), currentSerial);
commandBuffer->copyBuffer(elementArrayBufferVk->getVkBuffer().getHandle(), *bufferHandleOut, 2,
copies.data());
ANGLE_TRY(mDynamicLineLoopIndicesData->flush(contextVk));
ANGLE_TRY(mDynamicLineLoopIndicesData->flush(renderer->getDevice()));
return gl::NoError();
}
......@@ -1275,13 +1266,11 @@ void LineLoopHandler::destroy(VkDevice 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
// bindLineLoopIndexBuffer.
// Our first index is always 0 because that's how we set it up in createIndexBuffer*.
commandBuffer->drawIndexed(count + 1, 1, 0, 0, 0);
return gl::NoError();
}
ResourceVk *LineLoopHandler::getLineLoopBufferResource()
......@@ -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.
if (message == angle::SubjectMessage::CONTENTS_CHANGED)
{
mLineLoopIndexBuffer = VK_NULL_HANDLE;
mObserverBinding.reset();
}
}
......@@ -1768,6 +1757,21 @@ VkComponentSwizzle GetSwizzle(const GLenum swizzle)
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
ResourceVk::ResourceVk() : mCurrentWritingNode(nullptr)
......
......@@ -38,6 +38,7 @@ class Display;
namespace gl
{
struct Box;
class DrawCallParams;
struct Extents;
struct RasterizerState;
struct Rectangle;
......@@ -641,27 +642,32 @@ 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.
// This class' responsibility is to create index buffers needed to support line loops in Vulkan.
// In the setup phase of drawing, the createIndexBuffer method should be called with the
// current draw call parameters. If an element array buffer is bound for an indexed draw, use
// createIndexBufferFromElementArrayBuffer.
//
// 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
{
public:
LineLoopHandler();
~LineLoopHandler();
void bindIndexBuffer(VkIndexType indexType, CommandBuffer **commandBuffer);
gl::Error createIndexBuffer(ContextVk *contextVk, int firstVertex, int count);
gl::Error createIndexBufferFromElementArrayBuffer(ContextVk *contextVk,
BufferVk *bufferVk,
gl::Error createIndexBuffer(RendererVk *renderer,
const gl::DrawCallParams &drawCallParams,
VkBuffer *bufferHandleOut,
VkDeviceSize *offsetOut);
gl::Error createIndexBufferFromElementArrayBuffer(RendererVk *renderer,
BufferVk *elementArrayBufferVk,
VkIndexType indexType,
int count);
int indexCount,
VkBuffer *bufferHandleOut,
VkDeviceSize *bufferOffsetOut);
void destroy(VkDevice device);
gl::Error draw(int count, CommandBuffer *commandBuffer);
static void Draw(int count, CommandBuffer *commandBuffer);
ResourceVk *getLineLoopBufferResource();
......@@ -673,10 +679,6 @@ class LineLoopHandler final : angle::NonCopyable, angle::ObserverInterface
private:
angle::ObserverBinding mObserverBinding;
std::unique_ptr<DynamicBuffer> mDynamicLineLoopIndicesData;
VkBuffer mLineLoopIndexBuffer;
uint32_t mLineLoopIndexBufferOffset;
Optional<int> mLineLoopBufferFirstIndex;
Optional<int> mLineLoopBufferLastIndex;
};
class ImageHelper final : angle::NonCopyable
......@@ -771,6 +773,7 @@ VkCullModeFlags GetCullMode(const gl::RasterizerState &rasterState);
VkFrontFace GetFrontFace(GLenum frontFace);
VkSampleCountFlagBits GetSamples(GLint sampleCount);
VkComponentSwizzle GetSwizzle(const GLenum swizzle);
VkIndexType GetIndexType(GLenum elementType);
} // namespace gl_vk
// 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