mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
vulkan: use staging buffer for Buffer operations
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user