Browse Source

vulkan: use staging buffer for Buffer operations

niki 2 years ago
parent
commit
9a91cfd593

+ 79 - 9
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_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
 	case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_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_TEXEL: return VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+	case BUFFERUSAGE_SHADER_STORAGE: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
 	default:
 	default:
 		throw love::Exception("unsupported BufferUsage mode");
 		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)
 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)
 	: love::graphics::Buffer(gfx, settings, format, size, arraylength)
 	, usageFlags(settings.usageFlags)
 	, usageFlags(settings.usageFlags)
-	, vgfx(dynamic_cast<Graphics*>(gfx)) 
+	, vgfx(dynamic_cast<Graphics*>(gfx))
+	, zeroInitialize(settings.zeroInitialize)
 {
 {
 	loadVolatile();
 	loadVolatile();
 }
 }
@@ -70,14 +72,20 @@ bool Buffer::loadVolatile()
 	bufferInfo.size = getSize();
 	bufferInfo.size = getSize();
 	bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | getVulkanUsageFlags(usageFlags);
 	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.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);
 	auto result = vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo);
 	if (result != VK_SUCCESS)
 	if (result != VK_SUCCESS)
 		throw love::Exception("failed to create buffer");
 		throw love::Exception("failed to create buffer");
 
 
+	if (zeroInitialize)
+		vkCmdFillBuffer(vgfx->getCommandBufferForDataTransfer(), buffer, 0, VK_WHOLE_SIZE, 0);
+
 	if (usageFlags & BUFFERUSAGEFLAG_TEXEL)
 	if (usageFlags & BUFFERUSAGEFLAG_TEXEL)
 	{
 	{
 		VkBufferViewCreateInfo bufferViewInfo{};
 		VkBufferViewCreateInfo bufferViewInfo{};
@@ -129,21 +137,83 @@ ptrdiff_t Buffer::getTexelBufferHandle() const
 
 
 void *Buffer::map(MapType map, size_t offset, size_t size)
 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)
 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;
 	return true;
 }
 }
 
 
 void Buffer::unmap(size_t usedoffset, size_t usedsize)
 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)
 void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)

+ 4 - 1
src/modules/graphics/vulkan/Buffer.h

@@ -54,13 +54,16 @@ public:
 	ptrdiff_t getTexelBufferHandle() const override;
 	ptrdiff_t getTexelBufferHandle() const override;
 
 
 private:
 private:
-	// todo use a staging buffer for improved performance
+	bool zeroInitialize;
 	VkBuffer buffer = VK_NULL_HANDLE;
 	VkBuffer buffer = VK_NULL_HANDLE;
+	VkBuffer stagingBuffer = VK_NULL_HANDLE;
 	VkBufferView bufferView = VK_NULL_HANDLE;
 	VkBufferView bufferView = VK_NULL_HANDLE;
 	Graphics *vgfx = nullptr;
 	Graphics *vgfx = nullptr;
 	VmaAllocator allocator;
 	VmaAllocator allocator;
 	VmaAllocation allocation;
 	VmaAllocation allocation;
+	VmaAllocation stagingAllocation;
 	VmaAllocationInfo allocInfo;
 	VmaAllocationInfo allocInfo;
+	VmaAllocationInfo stagingAllocInfo;
 	BufferUsageFlags usageFlags;
 	BufferUsageFlags usageFlags;
 };
 };
 
 

+ 1 - 0
src/modules/graphics/vulkan/Graphics.cpp

@@ -526,6 +526,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
 	createDefaultShaders();
 	createDefaultShaders();
 	Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT];
 	Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT];
 	createQuadIndexBuffer();
 	createQuadIndexBuffer();
+	createFanIndexBuffer();
 
 
 	restoreState(states.back());
 	restoreState(states.back());