vulkan: use staging buffer for Buffer operations

This commit is contained in:
niki
2022-09-18 04:31:24 +02:00
parent bf6915ae73
commit 9a91cfd593
3 changed files with 84 additions and 10 deletions
+79 -9
View File
@@ -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<DataDeclaration> &format, const void *data, size_t size, size_t arraylength)
: love::graphics::Buffer(gfx, settings, format, size, arraylength)
, usageFlags(settings.usageFlags)
, vgfx(dynamic_cast<Graphics*>(gfx))
, vgfx(dynamic_cast<Graphics*>(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)
+4 -1
View File
@@ -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;
};
+1
View File
@@ -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());