vulkan: memory barriers for buffer copy/write operations.

This commit is contained in:
Sasha Szpakowski
2024-09-30 14:43:27 -03:00
parent 6d40eab097
commit 64e4eaec74
4 changed files with 71 additions and 5 deletions
+1 -1
View File
@@ -110,7 +110,7 @@ namespace opengl { extern love::graphics::Graphics *createInstance(); }
namespace metal { extern love::graphics::Graphics *createInstance(); }
#endif
#ifdef LOVE_GRAPHICS_VULKAN
namespace vulkan { extern love::graphics::Graphics* createInstance(); }
namespace vulkan { extern love::graphics::Graphics *createInstance(); }
#endif
static const Renderer rendererOrder[] = {
+63 -4
View File
@@ -84,7 +84,11 @@ bool Buffer::loadVolatile()
throw love::Exception("failed to create buffer");
if (zeroInitialize)
vkCmdFillBuffer(vgfx->getCommandBufferForDataTransfer(), buffer, 0, VK_WHOLE_SIZE, 0);
{
auto cmd = vgfx->getCommandBufferForDataTransfer();
vkCmdFillBuffer(cmd, buffer, 0, VK_WHOLE_SIZE, 0);
postGPUWriteBarrier(cmd);
}
if (initialData)
fill(0, size, initialData);
@@ -235,7 +239,10 @@ bool Buffer::fill(size_t offset, size_t size, const void *data)
bufferCopy.dstOffset = offset;
bufferCopy.size = size;
vkCmdCopyBuffer(vgfx->getCommandBufferForDataTransfer(), fillBuffer, buffer, 1, &bufferCopy);
auto cmd = vgfx->getCommandBufferForDataTransfer();
vkCmdCopyBuffer(cmd, fillBuffer, buffer, 1, &bufferCopy);
postGPUWriteBarrier(cmd);
vgfx->queueCleanUp([allocator = allocator, fillBuffer = fillBuffer, fillAllocation = fillAllocation]() {
vmaDestroyBuffer(allocator, fillBuffer, fillAllocation);
@@ -258,7 +265,10 @@ void Buffer::unmap(size_t usedoffset, size_t usedsize)
if (~memoryProperties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
vmaFlushAllocation(allocator, stagingAllocation, bufferCopy.srcOffset, usedsize);
vkCmdCopyBuffer(vgfx->getCommandBufferForDataTransfer(), stagingBuffer, buffer, 1, &bufferCopy);
auto cmd = vgfx->getCommandBufferForDataTransfer();
vkCmdCopyBuffer(cmd, stagingBuffer, buffer, 1, &bufferCopy);
postGPUWriteBarrier(cmd);
vgfx->queueCleanUp([allocator = allocator, stagingBuffer = stagingBuffer, stagingAllocation = stagingAllocation]() {
vmaDestroyBuffer(allocator, stagingBuffer, stagingAllocation);
@@ -268,7 +278,9 @@ void Buffer::unmap(size_t usedoffset, size_t usedsize)
void Buffer::clearInternal(size_t offset, size_t size)
{
vkCmdFillBuffer(vgfx->getCommandBufferForDataTransfer(), buffer, offset, size, 0);
auto cmd = vgfx->getCommandBufferForDataTransfer();
vkCmdFillBuffer(cmd, buffer, offset, size, 0);
postGPUWriteBarrier(cmd);
}
void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
@@ -281,6 +293,53 @@ void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t de
bufferCopy.size = size;
vkCmdCopyBuffer(commandBuffer, buffer, (VkBuffer) dest->getHandle(), 1, &bufferCopy);
((Buffer *)dest)->postGPUWriteBarrier(commandBuffer);
}
void Buffer::postGPUWriteBarrier(VkCommandBuffer cmd)
{
VkMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
VkPipelineStageFlags dstStageMask = 0;
addPostGPUWriteBarrierFlags(barrier.dstAccessMask, dstStageMask);
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 1, &barrier, 0, nullptr, 0, nullptr);
}
void Buffer::addPostGPUWriteBarrierFlags(VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags)
{
// All buffers can be copied to and from.
dstAccessFlags |= VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
if (usageFlags & BUFFERUSAGEFLAG_VERTEX)
{
dstAccessFlags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_INDEX)
{
dstAccessFlags |= VK_ACCESS_INDEX_READ_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_TEXEL)
{
dstAccessFlags |= VK_ACCESS_SHADER_READ_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_SHADER_STORAGE)
{
dstAccessFlags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_INDIRECT_ARGUMENTS)
{
dstAccessFlags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
}
}
} // vulkan
+3
View File
@@ -55,6 +55,9 @@ public:
ptrdiff_t getHandle() const override;
ptrdiff_t getTexelBufferHandle() const override;
void postGPUWriteBarrier(VkCommandBuffer cmd);
void addPostGPUWriteBarrierFlags(VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags);
private:
void clearInternal(size_t offset, size_t size) override;
+4
View File
@@ -21,6 +21,7 @@
#include "Texture.h"
#include "Graphics.h"
#include "Vulkan.h"
#include "Buffer.h"
#include <limits>
@@ -683,6 +684,9 @@ void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const
}
else
vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, (VkBuffer)dest->getHandle(), 1, &region);
// TODO: This could be combined with the cmdTransitionImageLayout barrier.
((Buffer *)dest)->postGPUWriteBarrier(commandBuffer);
}
} // vulkan