From 64e4eaec749c7935e118971146c6510503cb5c2f Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Mon, 30 Sep 2024 14:43:27 -0300 Subject: [PATCH] vulkan: memory barriers for buffer copy/write operations. --- src/modules/graphics/Graphics.cpp | 2 +- src/modules/graphics/vulkan/Buffer.cpp | 67 +++++++++++++++++++++++-- src/modules/graphics/vulkan/Buffer.h | 3 ++ src/modules/graphics/vulkan/Texture.cpp | 4 ++ 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index f9c0a604c..f70889321 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -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[] = { diff --git a/src/modules/graphics/vulkan/Buffer.cpp b/src/modules/graphics/vulkan/Buffer.cpp index 4cf4f45d4..33cb0e965 100644 --- a/src/modules/graphics/vulkan/Buffer.cpp +++ b/src/modules/graphics/vulkan/Buffer.cpp @@ -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 diff --git a/src/modules/graphics/vulkan/Buffer.h b/src/modules/graphics/vulkan/Buffer.h index 41d64b6cd..fda7b7295 100644 --- a/src/modules/graphics/vulkan/Buffer.h +++ b/src/modules/graphics/vulkan/Buffer.h @@ -55,6 +55,9 @@ class Buffer final 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; diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 157cac94d..bbf4f60e1 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -21,6 +21,7 @@ #include "Texture.h" #include "Graphics.h" #include "Vulkan.h" +#include "Buffer.h" #include @@ -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, ®ion); + + // TODO: This could be combined with the cmdTransitionImageLayout barrier. + ((Buffer *)dest)->postGPUWriteBarrier(commandBuffer); } } // vulkan