Vulkan: Use global buffer barriers.
This switches from using resource barriers for buffers to using global
barriers. This matches the general advised best practice. It also
allows us to combine multiple barriers into one. On a draw we might
combine all the vertex and index barriers into a single barrier call.
We implement this using a bit of extra state tracking in BufferHelper.
Bug: angleproject:2828
Change-Id: I196b368804ff50e60d085687a643e5566ba1c5b6
Reviewed-on: https://chromium-review.googlesource.com/c/1309977
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/BufferVk.cpp b/src/libANGLE/renderer/vulkan/BufferVk.cpp
index bbe9159..d456ffe 100644
--- a/src/libANGLE/renderer/vulkan/BufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/BufferVk.cpp
@@ -213,43 +213,8 @@
stagingBuffer.getDeviceMemory().unmap(device);
// Enqueue a copy command on the GPU.
- // 'beginWriteResource' will stop any subsequent rendering from using the old buffer data,
- // by marking any current read operations / command buffers as 'finished'.
- vk::CommandBuffer *commandBuffer = nullptr;
- ANGLE_TRY(mBuffer.recordCommands(contextVk, &commandBuffer));
-
- // Insert a barrier to ensure reads from the buffer are complete.
- // TODO(jmadill): Insert minimal barriers.
- VkBufferMemoryBarrier bufferBarrier = {};
- bufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
- bufferBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
- bufferBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- bufferBarrier.srcQueueFamilyIndex = 0;
- bufferBarrier.dstQueueFamilyIndex = 0;
- bufferBarrier.buffer = mBuffer.getBuffer().getHandle();
- bufferBarrier.offset = offset;
- bufferBarrier.size = static_cast<VkDeviceSize>(size);
-
- commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
- VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 1,
- &bufferBarrier, 0, nullptr);
-
VkBufferCopy copyRegion = {0, offset, size};
- commandBuffer->copyBuffer(stagingBuffer.getBuffer(), mBuffer.getBuffer(), 1, ©Region);
-
- // Insert a barrier to ensure copy has done.
- // TODO(jie.a.chen@intel.com): Insert minimal barriers.
- bufferBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- bufferBarrier.dstAccessMask =
- VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
- VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT |
- VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT |
- VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT;
-
- commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
- VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 1,
- &bufferBarrier, 0, nullptr);
+ ANGLE_TRY(mBuffer.copyFromBuffer(contextVk, stagingBuffer.getBuffer(), copyRegion));
// Immediately release staging buffer. We should probably be using a DynamicBuffer here.
renderer->releaseObject(renderer->getCurrentQueueSerial(), &stagingBuffer);
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.cpp b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
index 6754132..bc9363c 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.cpp
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
@@ -33,17 +33,17 @@
ASSERT(!commandBuffer->valid());
VkCommandBufferAllocateInfo createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- createInfo.commandPool = commandPool.getHandle();
- createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
- createInfo.commandBufferCount = 1;
+ createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ createInfo.commandPool = commandPool.getHandle();
+ createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
+ createInfo.commandBufferCount = 1;
ANGLE_TRY(commandBuffer->init(context, createInfo));
VkCommandBufferBeginInfo beginInfo = {};
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- beginInfo.pInheritanceInfo = &inheritanceInfo;
+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+ beginInfo.pInheritanceInfo = &inheritanceInfo;
ANGLE_TRY(commandBuffer->begin(context, beginInfo));
return angle::Result::Continue();
@@ -297,7 +297,9 @@
mQueryPool(VK_NULL_HANDLE),
mQueryIndex(0),
mHasChildren(false),
- mVisitedState(VisitedState::Unvisited)
+ mVisitedState(VisitedState::Unvisited),
+ mGlobalMemoryBarrierSrcAccess(0),
+ mGlobalMemoryBarrierDstAccess(0)
{
}
@@ -323,14 +325,14 @@
ASSERT(!mHasChildren);
VkCommandBufferInheritanceInfo inheritanceInfo = {};
- inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
- inheritanceInfo.renderPass = VK_NULL_HANDLE;
- inheritanceInfo.subpass = 0;
- inheritanceInfo.framebuffer = VK_NULL_HANDLE;
+ inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
+ inheritanceInfo.renderPass = VK_NULL_HANDLE;
+ inheritanceInfo.subpass = 0;
+ inheritanceInfo.framebuffer = VK_NULL_HANDLE;
inheritanceInfo.occlusionQueryEnable =
context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
- inheritanceInfo.queryFlags = 0;
- inheritanceInfo.pipelineStatistics = 0;
+ inheritanceInfo.queryFlags = 0;
+ inheritanceInfo.pipelineStatistics = 0;
ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
&mOutsideRenderPassCommands));
@@ -351,14 +353,14 @@
&compatibleRenderPass));
VkCommandBufferInheritanceInfo inheritanceInfo = {};
- inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
- inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
- inheritanceInfo.subpass = 0;
- inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
+ inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
+ inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
+ inheritanceInfo.subpass = 0;
+ inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
inheritanceInfo.occlusionQueryEnable =
context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
- inheritanceInfo.queryFlags = 0;
- inheritanceInfo.pipelineStatistics = 0;
+ inheritanceInfo.queryFlags = 0;
+ inheritanceInfo.pipelineStatistics = 0;
ANGLE_TRY(InitAndBeginCommandBuffer(
context, context->getRenderer()->getCommandPool(), inheritanceInfo,
@@ -429,6 +431,12 @@
mQueryIndex = queryIndex;
}
+void CommandGraphNode::addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess)
+{
+ mGlobalMemoryBarrierSrcAccess |= srcAccess;
+ mGlobalMemoryBarrierDstAccess |= dstAccess;
+}
+
void CommandGraphNode::setHasChildren()
{
mHasChildren = true;
@@ -480,6 +488,21 @@
case CommandGraphNodeFunction::Generic:
ASSERT(mQueryPool == VK_NULL_HANDLE);
+ // Record the deferred pipeline barrier if necessary.
+ ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
+ if (mGlobalMemoryBarrierSrcAccess)
+ {
+ VkMemoryBarrier memoryBarrier = {};
+ memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+ memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
+ memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
+
+ // Use the top of pipe stage to keep the state management simple.
+ primaryCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 1,
+ &memoryBarrier, 0, nullptr, 0, nullptr);
+ }
+
if (mOutsideRenderPassCommands.valid())
{
ANGLE_TRY(mOutsideRenderPassCommands.end(context));
@@ -630,10 +653,10 @@
mLastBarrierIndex = kInvalidNodeIndex;
VkCommandBufferAllocateInfo primaryInfo = {};
- primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- primaryInfo.commandPool = commandPool->getHandle();
- primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- primaryInfo.commandBufferCount = 1;
+ primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ primaryInfo.commandPool = commandPool->getHandle();
+ primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ primaryInfo.commandBufferCount = 1;
ANGLE_TRY(primaryCommandBufferOut->init(context, primaryInfo));
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.h b/src/libANGLE/renderer/vulkan/CommandGraph.h
index eb20678..21263f4 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.h
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.h
@@ -107,6 +107,8 @@
void setQueryPool(const QueryPool *queryPool, uint32_t queryIndex);
+ void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess);
+
private:
void setHasChildren();
@@ -142,6 +144,10 @@
// Additional diagnostic information.
CommandGraphResourceType mResourceType;
uintptr_t mResourceID;
+
+ // For global memory barriers.
+ VkFlags mGlobalMemoryBarrierSrcAccess;
+ VkFlags mGlobalMemoryBarrierDstAccess;
};
// This is a helper class for back-end objects used in Vk command buffers. It records a serial
@@ -214,11 +220,17 @@
// Called when 'this' object changes, but we'd like to start a new command buffer later.
void finishCurrentCommands(RendererVk *renderer);
+ // Store a deferred memory barrier. Will be recorded into a primary command buffer at submit.
+ void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess)
+ {
+ ASSERT(mCurrentWritingNode);
+ mCurrentWritingNode->addGlobalMemoryBarrier(srcAccess, dstAccess);
+ }
+
protected:
explicit RecordableGraphResource(CommandGraphResourceType resourceType);
private:
-
// Returns true if this node has a current writing node with no children.
bool hasChildlessWritingNode() const
{
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index 2a3fd8d..08a70e6 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -428,14 +428,19 @@
mProgram->getState().getMaxActiveAttribLocation(),
mVertexArray->getCurrentArrayBufferHandles(), mVertexArray->getCurrentArrayBufferOffsets());
- const auto &arrayBufferResources = mVertexArray->getCurrentArrayBufferResources();
+ const auto &arrayBufferResources = mVertexArray->getCurrentArrayBuffers();
+
+ vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer();
for (size_t attribIndex : context->getStateCache().getActiveBufferedAttribsMask())
{
- if (arrayBufferResources[attribIndex])
- arrayBufferResources[attribIndex]->addReadDependency(
- mDrawFramebuffer->getFramebuffer());
+ vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex];
+ if (arrayBuffer)
+ {
+ arrayBuffer->onFramebufferRead(framebuffer, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT);
+ }
}
+
return angle::Result::Continue();
}
@@ -446,11 +451,11 @@
mVertexArray->getCurrentElementArrayBufferOffset(),
gl_vk::GetIndexType(mCurrentDrawElementsType));
- vk::RecordableGraphResource *elementArrayBufferResource =
- mVertexArray->getCurrentElementArrayBufferResource();
- if (elementArrayBufferResource)
+ vk::BufferHelper *elementArrayBuffer = mVertexArray->getCurrentElementArrayBuffer();
+ if (elementArrayBuffer)
{
- elementArrayBufferResource->addReadDependency(mDrawFramebuffer->getFramebuffer());
+ vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer();
+ elementArrayBuffer->onFramebufferRead(framebuffer, VK_ACCESS_INDEX_READ_BIT);
}
return angle::Result::Continue();
}
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
index 9182135..e39b341 100644
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
@@ -64,7 +64,7 @@
: VertexArrayImpl(state),
mCurrentArrayBufferHandles{},
mCurrentArrayBufferOffsets{},
- mCurrentArrayBufferResources{},
+ mCurrentArrayBuffers{},
mCurrentArrayBufferFormats{},
mCurrentArrayBufferStrides{},
mCurrentArrayBufferConversion{{
@@ -74,7 +74,7 @@
mCurrentArrayBufferConversionCanRelease{},
mCurrentElementArrayBufferHandle(VK_NULL_HANDLE),
mCurrentElementArrayBufferOffset(0),
- mCurrentElementArrayBufferResource(nullptr),
+ mCurrentElementArrayBuffer(nullptr),
mPackedInputBindings{},
mPackedInputAttributes{},
mDynamicVertexData(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, kDynamicVertexDataSize),
@@ -85,7 +85,7 @@
{
mCurrentArrayBufferHandles.fill(VK_NULL_HANDLE);
mCurrentArrayBufferOffsets.fill(0);
- mCurrentArrayBufferResources.fill(nullptr);
+ mCurrentArrayBuffers.fill(nullptr);
for (vk::DynamicBuffer &buffer : mCurrentArrayBufferConversion)
{
@@ -253,15 +253,15 @@
gl::Buffer *bufferGL = mState.getElementArrayBuffer();
if (bufferGL)
{
- BufferVk *bufferVk = vk::GetImpl(bufferGL);
- mCurrentElementArrayBufferResource = &bufferVk->getBuffer();
+ BufferVk *bufferVk = vk::GetImpl(bufferGL);
+ mCurrentElementArrayBuffer = &bufferVk->getBuffer();
mCurrentElementArrayBufferHandle =
bufferVk->getBuffer().getBuffer().getHandle();
}
else
{
- mCurrentElementArrayBufferResource = nullptr;
- mCurrentElementArrayBufferHandle = VK_NULL_HANDLE;
+ mCurrentElementArrayBuffer = nullptr;
+ mCurrentElementArrayBufferHandle = VK_NULL_HANDLE;
}
mCurrentElementArrayBufferOffset = 0;
@@ -326,12 +326,12 @@
ANGLE_TRY(convertVertexBuffer(contextVk, bufferVk, binding, attribIndex));
- mCurrentArrayBufferResources[attribIndex] = nullptr;
- releaseConversion = false;
+ mCurrentArrayBuffers[attribIndex] = nullptr;
+ releaseConversion = false;
}
else
{
- mCurrentArrayBufferResources[attribIndex] = &bufferVk->getBuffer();
+ mCurrentArrayBuffers[attribIndex] = &bufferVk->getBuffer();
mCurrentArrayBufferHandles[attribIndex] =
bufferVk->getBuffer().getBuffer().getHandle();
mCurrentArrayBufferOffsets[attribIndex] = binding.getOffset();
@@ -340,9 +340,9 @@
}
else
{
- mCurrentArrayBufferResources[attribIndex] = nullptr;
- mCurrentArrayBufferHandles[attribIndex] = VK_NULL_HANDLE;
- mCurrentArrayBufferOffsets[attribIndex] = 0;
+ mCurrentArrayBuffers[attribIndex] = nullptr;
+ mCurrentArrayBufferHandles[attribIndex] = VK_NULL_HANDLE;
+ mCurrentArrayBufferOffsets[attribIndex] = 0;
mCurrentArrayBufferStrides[attribIndex] =
mCurrentArrayBufferFormats[attribIndex]->bufferFormat().pixelBytes;
}
@@ -352,10 +352,10 @@
contextVk->invalidateDefaultAttribute(attribIndex);
// These will be filled out by the ContextVk.
- mCurrentArrayBufferResources[attribIndex] = nullptr;
- mCurrentArrayBufferHandles[attribIndex] = VK_NULL_HANDLE;
- mCurrentArrayBufferOffsets[attribIndex] = 0;
- mCurrentArrayBufferStrides[attribIndex] = 0;
+ mCurrentArrayBuffers[attribIndex] = nullptr;
+ mCurrentArrayBufferHandles[attribIndex] = VK_NULL_HANDLE;
+ mCurrentArrayBufferOffsets[attribIndex] = 0;
+ mCurrentArrayBufferStrides[attribIndex] = 0;
mCurrentArrayBufferFormats[attribIndex] =
&renderer->getFormat(angle::FormatID::R32G32B32A32_FLOAT);
}
@@ -582,10 +582,10 @@
{
if (!mState.getEnabledAttributesMask().test(attribIndex))
{
- mCurrentArrayBufferHandles[attribIndex] = bufferHandle;
- mCurrentArrayBufferOffsets[attribIndex] = offset;
- mCurrentArrayBufferResources[attribIndex] = nullptr;
- mCurrentArrayBufferStrides[attribIndex] = 0;
+ mCurrentArrayBufferHandles[attribIndex] = bufferHandle;
+ mCurrentArrayBufferOffsets[attribIndex] = offset;
+ mCurrentArrayBuffers[attribIndex] = nullptr;
+ mCurrentArrayBufferStrides[attribIndex] = 0;
mCurrentArrayBufferFormats[attribIndex] =
&renderer->getFormat(angle::FormatID::R32G32B32A32_FIXED);
mDirtyPackedInputs.set(attribIndex);
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.h b/src/libANGLE/renderer/vulkan/VertexArrayVk.h
index d91817b..1fbd7f4 100644
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.h
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.h
@@ -65,9 +65,9 @@
return mCurrentArrayBufferOffsets;
}
- const gl::AttribArray<vk::RecordableGraphResource *> &getCurrentArrayBufferResources() const
+ const gl::AttribArray<vk::BufferHelper *> &getCurrentArrayBuffers() const
{
- return mCurrentArrayBufferResources;
+ return mCurrentArrayBuffers;
}
VkBuffer getCurrentElementArrayBufferHandle() const { return mCurrentElementArrayBufferHandle; }
@@ -82,10 +82,7 @@
mCurrentElementArrayBufferOffset = reinterpret_cast<VkDeviceSize>(offset);
}
- vk::RecordableGraphResource *getCurrentElementArrayBufferResource() const
- {
- return mCurrentElementArrayBufferResource;
- }
+ vk::BufferHelper *getCurrentElementArrayBuffer() const { return mCurrentElementArrayBuffer; }
angle::Result updateIndexTranslation(ContextVk *contextVk,
GLsizei indexCount,
@@ -121,14 +118,14 @@
gl::AttribArray<VkBuffer> mCurrentArrayBufferHandles;
gl::AttribArray<VkDeviceSize> mCurrentArrayBufferOffsets;
- gl::AttribArray<vk::RecordableGraphResource *> mCurrentArrayBufferResources;
+ gl::AttribArray<vk::BufferHelper *> mCurrentArrayBuffers;
gl::AttribArray<const vk::Format *> mCurrentArrayBufferFormats;
gl::AttribArray<GLuint> mCurrentArrayBufferStrides;
gl::AttribArray<vk::DynamicBuffer> mCurrentArrayBufferConversion;
gl::AttribArray<bool> mCurrentArrayBufferConversionCanRelease;
VkBuffer mCurrentElementArrayBufferHandle;
VkDeviceSize mCurrentElementArrayBufferOffset;
- vk::RecordableGraphResource *mCurrentElementArrayBufferResource;
+ vk::BufferHelper *mCurrentElementArrayBuffer;
// Keep a cache of binding and attribute descriptions for easy pipeline updates.
// This is copied out of here into the pipeline description on a Context state change.
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
index 877609f..5ab1ccd 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
@@ -887,7 +887,10 @@
// BufferHelper implementation.
BufferHelper::BufferHelper()
- : RecordableGraphResource(CommandGraphResourceType::Buffer), mMemoryPropertyFlags{}
+ : RecordableGraphResource(CommandGraphResourceType::Buffer),
+ mMemoryPropertyFlags{},
+ mCurrentWriteAccess(0),
+ mCurrentReadAccess(0)
{
}
@@ -908,6 +911,47 @@
renderer->releaseObject(getStoredQueueSerial(), &mDeviceMemory);
}
+void BufferHelper::onFramebufferRead(FramebufferHelper *framebuffer, VkAccessFlagBits accessType)
+{
+ addReadDependency(framebuffer);
+
+ if ((mCurrentWriteAccess != 0) && ((mCurrentReadAccess & accessType) == 0))
+ {
+ framebuffer->addGlobalMemoryBarrier(mCurrentWriteAccess, accessType);
+ mCurrentReadAccess |= accessType;
+ }
+}
+
+angle::Result BufferHelper::copyFromBuffer(ContextVk *contextVk,
+ const Buffer &buffer,
+ const VkBufferCopy ©Region)
+{
+ // 'recordCommands' will implicitly stop any reads from using the old buffer data.
+ vk::CommandBuffer *commandBuffer = nullptr;
+ ANGLE_TRY(recordCommands(contextVk, &commandBuffer));
+
+ if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
+ {
+ // Insert a barrier to ensure reads/writes are complete.
+ // Use a global memory barrier to keep things simple.
+ VkMemoryBarrier memoryBarrier = {};
+ memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+ memoryBarrier.srcAccessMask = mCurrentReadAccess;
+ memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memoryBarrier, 0,
+ nullptr, 0, nullptr);
+
+ mCurrentWriteAccess = VK_ACCESS_TRANSFER_WRITE_BIT;
+ mCurrentReadAccess = 0;
+ }
+
+ commandBuffer->copyBuffer(buffer, mBuffer, 1, ©Region);
+
+ return angle::Result::Continue();
+}
+
// ImageHelper implementation.
ImageHelper::ImageHelper()
: RecordableGraphResource(CommandGraphResourceType::Image),
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
index 4d8b1ff..5e2f6c0 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
@@ -369,6 +369,8 @@
DynamicBuffer mDynamicIndexBuffer;
};
+class FramebufferHelper;
+
class BufferHelper final : public RecordableGraphResource
{
public:
@@ -384,6 +386,14 @@
const Buffer &getBuffer() const { return mBuffer; }
const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
+ // Helper for setting the graph dependencies *and* setting the appropriate barrier.
+ void onFramebufferRead(FramebufferHelper *framebuffer, VkAccessFlagBits accessType);
+
+ // Also implicitly sets up the correct barriers.
+ angle::Result copyFromBuffer(ContextVk *contextVk,
+ const Buffer &buffer,
+ const VkBufferCopy ©Region);
+
private:
// Vulkan objects.
Buffer mBuffer;
@@ -391,6 +401,10 @@
// Cached properties.
VkMemoryPropertyFlags mMemoryPropertyFlags;
+
+ // For memory barriers.
+ VkFlags mCurrentWriteAccess;
+ VkFlags mCurrentReadAccess;
};
class ImageHelper final : public RecordableGraphResource