From 9a91cfd593ec9fe44d987f0ca212eaa6c3054d2b Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 18 Sep 2022 04:31:24 +0200 Subject: [PATCH] vulkan: use staging buffer for Buffer operations --- src/modules/graphics/vulkan/Buffer.cpp | 88 +++++++++++++++++++++--- src/modules/graphics/vulkan/Buffer.h | 5 +- src/modules/graphics/vulkan/Graphics.cpp | 1 + 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/modules/graphics/vulkan/Buffer.cpp b/src/modules/graphics/vulkan/Buffer.cpp index 391a758d3..d9387ca1b 100644 --- a/src/modules/graphics/vulkan/Buffer.cpp +++ b/src/modules/graphics/vulkan/Buffer.cpp @@ -36,6 +36,7 @@ static VkBufferUsageFlags getUsageBit(BufferUsage mode) case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; case BUFFERUSAGE_TEXEL: return VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; + case BUFFERUSAGE_SHADER_STORAGE: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; default: throw love::Exception("unsupported BufferUsage mode"); } @@ -56,7 +57,8 @@ static VkBufferUsageFlags getVulkanUsageFlags(BufferUsageFlags flags) Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) : love::graphics::Buffer(gfx, settings, format, size, arraylength) , usageFlags(settings.usageFlags) - , vgfx(dynamic_cast(gfx)) + , vgfx(dynamic_cast(gfx)) + , zeroInitialize(settings.zeroInitialize) { loadVolatile(); } @@ -70,14 +72,20 @@ bool Buffer::loadVolatile() bufferInfo.size = getSize(); bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | getVulkanUsageFlags(usageFlags); - VmaAllocationCreateInfo allocCreateInfo = {}; + VmaAllocationCreateInfo allocCreateInfo{}; allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; - allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + if (dataUsage == BUFFERDATAUSAGE_READBACK) + allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + else if ((bufferInfo.usage | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) || (bufferInfo.usage | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)) + allocCreateInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; auto result = vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo); if (result != VK_SUCCESS) throw love::Exception("failed to create buffer"); + if (zeroInitialize) + vkCmdFillBuffer(vgfx->getCommandBufferForDataTransfer(), buffer, 0, VK_WHOLE_SIZE, 0); + if (usageFlags & BUFFERUSAGEFLAG_TEXEL) { VkBufferViewCreateInfo bufferViewInfo{}; @@ -129,21 +137,83 @@ ptrdiff_t Buffer::getTexelBufferHandle() const void *Buffer::map(MapType map, size_t offset, size_t size) { - char *data = (char*)allocInfo.pMappedData; - return (void*) (data + offset); + if (dataUsage == BUFFERDATAUSAGE_READBACK) + { + char *data = (char*)allocInfo.pMappedData; + return (void*) (data + offset); + } + else + { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + + VmaAllocationCreateInfo allocInfo{}; + allocInfo.usage = VMA_MEMORY_USAGE_AUTO; + allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + + if (vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &stagingBuffer, &stagingAllocation, &stagingAllocInfo) != VK_SUCCESS) + throw love::Exception("failed to create staging buffer"); + + return stagingAllocInfo.pMappedData; + } } bool Buffer::fill(size_t offset, size_t size, const void *data) { - void *dst = (void*)((char*)allocInfo.pMappedData + offset); - memcpy(dst, data, size); + if (dataUsage == BUFFERDATAUSAGE_READBACK) + { + void *dst = (void*)((char*)allocInfo.pMappedData + offset); + memcpy(dst, data, size); + } + else + { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + + VmaAllocationCreateInfo allocInfo{}; + allocInfo.usage = VMA_MEMORY_USAGE_AUTO; + allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + + VkBuffer fillBuffer; + VmaAllocation fillAllocation; + VmaAllocationInfo fillAllocInfo; + + if (vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &fillBuffer, &fillAllocation, &fillAllocInfo) != VK_SUCCESS) + throw love::Exception("failed to create fill buffer"); + + memcpy(fillAllocInfo.pMappedData, data, size); + + VkBufferCopy bufferCopy{}; + bufferCopy.srcOffset = offset; + bufferCopy.size = size; + + vkCmdCopyBuffer(vgfx->getCommandBufferForDataTransfer(), fillBuffer, buffer, 1, &bufferCopy); + + vgfx->queueCleanUp([allocator = allocator, fillBuffer = fillBuffer, fillAllocation = fillAllocation]() { + vmaDestroyBuffer(allocator, fillBuffer, fillAllocation); + }); + } return true; } void Buffer::unmap(size_t usedoffset, size_t usedsize) { - (void)usedoffset; - (void)usedsize; + if (dataUsage != BUFFERDATAUSAGE_READBACK) + { + VkBufferCopy bufferCopy{}; + bufferCopy.srcOffset = usedoffset; + bufferCopy.size = usedsize; + + vkCmdCopyBuffer(vgfx->getCommandBufferForDataTransfer(), stagingBuffer, buffer, 1, &bufferCopy); + + vgfx->queueCleanUp([allocator = allocator, stagingBuffer = stagingBuffer, stagingAllocation = stagingAllocation]() { + vmaDestroyBuffer(allocator, stagingBuffer, stagingAllocation); + }); + } } void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) diff --git a/src/modules/graphics/vulkan/Buffer.h b/src/modules/graphics/vulkan/Buffer.h index 1a834a10e..33bdaebe1 100644 --- a/src/modules/graphics/vulkan/Buffer.h +++ b/src/modules/graphics/vulkan/Buffer.h @@ -54,13 +54,16 @@ public: ptrdiff_t getTexelBufferHandle() const override; private: - // todo use a staging buffer for improved performance + bool zeroInitialize; VkBuffer buffer = VK_NULL_HANDLE; + VkBuffer stagingBuffer = VK_NULL_HANDLE; VkBufferView bufferView = VK_NULL_HANDLE; Graphics *vgfx = nullptr; VmaAllocator allocator; VmaAllocation allocation; + VmaAllocation stagingAllocation; VmaAllocationInfo allocInfo; + VmaAllocationInfo stagingAllocInfo; BufferUsageFlags usageFlags; }; diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 4339aed29..e4aef3078 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -526,6 +526,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int createDefaultShaders(); Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT]; createQuadIndexBuffer(); + createFanIndexBuffer(); restoreState(states.back());