vulkan中从CPU到GPU传输数据,暂存缓冲区(staging buffer)的必要性

Staging Buffer” ,可翻译成暂存缓冲区临时缓冲区,在使用诸如Vulkan、DirectX等现代图形API时,经常用于充当主机和GPU之间的桥梁,以进行高效的数据传输。要明确知道,staging buffer是显存上开辟的

在使用staging buffer的情况下,从CPU到GPU的数据传输流程:

  • 在GPU申请一块内存,并设置为主机可见(可以映射其地址)
  • 把CPU端内存中存放的目标数据拷贝到staging buffer中
  • 创建另一个相同大小的显存块,对主机不可见
  • 从staging buffer拷贝数据到该buffer中
  • 删除主机可见的staging buffer
  • 使用这块显存来渲染

一个创建Index Buffer的示例:

VulkanIndexBuffer::VulkanIndexBuffer(void* data, uint64_t size)
	: m_Size(size)
{
	// 这里通过Buffer类申请了堆区空间,并把形参的数据拷贝进去
	m_LocalData = Buffer::Copy(data, size);		

	// 封装的一个类,用于简化显存块的分配过程
	VulkanAllocator allocator("IndexBuffer");	

	if (usingStaging)
	{
		// Staging Buffer
		// 注意usage参数:传输源(我们要从staging buffer拷贝数据到index buffer)
		VkBufferCreateInfo bufferCreateInfo{};
		bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
		bufferCreateInfo.size = instance->m_Size;
		bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;	/
		bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
		
		// 这里给分配器传的flags是CPU_TO_GPU,即CPU可见
		// VmaAllocation对象才是GPU显存块的代表,VkBuffer仅仅是提供缓存大小、用途等信息的
		VkBuffer stagingBuffer;
		VmaAllocation stagingBufferAllocation = allocator.AllocateBuffer(bufferCreateInfo, VMA_MEMORY_USAGE_CPU_TO_GPU, stagingBuffer);
	
		// MapMemory和UnMapMemory:将GPU显存块(CPU可见的)的地址映射到程序端的虚拟地址空间,然后通过指针就能写入数据到这块内存了
		uint8_t* destData = allocator.MapMemory<uint8_t>(stagingBufferAllocation);
		memcpy(destData, this->m_LocalData.Data, this->m_LocalData.Size);
		allocator.UnmapMemory(stagingBufferAllocation);
	
		// Index Buffer
		// 注意usage参数:传输的目标,且指明是用作Index buffer(vulkan会对此显存块进行相应优化)
		VkBufferCreateInfo indexBufferCreateInfo = {};	
		indexBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
		indexBufferCreateInfo.size = instance->m_Size;
		indexBufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;	
		
		// 注意flags参数:仅GPU(因此它不能进行映射,也就是CPU不可见,不能传输数据,因此需要staging buffer)
		this->m_MemoryAllocation = allocator.AllocateBuffer(indexBufferCreateInfo, VMA_MEMORY_USAGE_GPU_ONLY, instance->m_IndexBuffer);	
	
		// 创建/获取 支持传输指令的command buffer来记录传输指令(vkCmdCopyBuffer)
		// true为调用vkBeginCommandBuffer函数,即创建该commandbuffer的同时开始指令记录
		VkCommandBuffer copyCmd = device->GetCommandBuffer(true);
		
		// 记录指令
		VkBufferCopy copyRegion = {};
		copyRegion.size = this->m_LocalData.Size;
		vkCmdCopyBuffer(copyCmd, stagingBuffer,this->m_IndexBuffer,	1, &copyRegion);
		
		// Flush意味着提交给指令队列并销毁该comman buffer 因为只是一个复制指令而已,用完就销毁该commandbuffer
		device->FlushCommandBuffer(copyCmd);
		
		// staging buffer已无用,须释放
		allocator.DestroyBuffer(stagingBuffer, stagingBufferAllocation);
	}
	else
	{
		VkBufferCreateInfo indexbufferCreateInfo = {};
		indexbufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
		indexbufferCreateInfo.size = instance->m_Size;
		indexbufferCreateInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
		
		// 如果不用stagingbuffer,那indexBuffer就需要CPU可见,可读可写,会影响效率,禁用很多优化
		auto bufferAlloc = allocator.AllocateBuffer(indexbufferCreateInfo, VMA_MEMORY_USAGE_CPU_TO_GPU, instance->m_VulkanBuffer);
	
		void* dstBuffer = allocator.MapMemory<void>(bufferAlloc);
		memcpy(dstBuffer, instance->m_LocalData.Data, instance->m_Size);
		allocator.UnmapMemory(bufferAlloc);
	}
}

vulkan中,分配显存的流程参考这篇文章:https://blog.csdn.net/Motarookie/article/details/135655035

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
在进行应用性能优化时,可以从多个方面入手,包括 CPUGPU 以及内存等方面。 一、CPU 优化 1. 优化算法 算法是影响 CPU 性能的最重要因素之一。开发者需要选择高效的算法来实现应用功能。 2. 多线程优化 多线程技术可以将 CPU 负载分担到多个线程上,提高 CPU 利用率。但是,多线程也会带来一些问题,例如线程同步和资源竞争等。因此,开发者需要合理使用多线程技术,避免出现问题。 3. 减少循环次数 循环是 CPU 执行时间最长的操作之一。因此,开发者需要尽可能减少循环次数,避免无谓的计算。 二、GPU 优化 1. 减少纹理使用 纹理是 GPU 计算密集型的操作之一。为了减少 GPU 负载,开发者需要尽可能减少纹理的使用。例如,可以将多张小纹理合并成一张大纹理,从而减少纹理切换次数。 2. 硬件加速 现代 GPU 支持硬件加速技术,例如 OpenGL、Vulkan 等。使用这些技术可以大大提高 GPU 渲染速度,但是,开发者需要了解这些技术的使用方法,避免出现问题。 3. 渲染批处理 渲染批处理可以将多个渲染操作合并成一个批处理,从而减少 GPU 负载。例如,可以将多个 UI 控件的渲染合并成一个批处理,从而提高 GPU 渲染速度。 三、内存优化 1. 内存使用监控 开发者需要使用内存使用监控工具来监控应用的内存使用情况,避免出现内存泄漏或内存占用过高的问题。 2. 内存复用 内存复用可以避免频繁的内存分配和释放,从而减少内存占用。例如,可以使用对象池技术来复用对象,避免频繁创建和销毁对象。 3. 内存压缩 内存压缩可以将内存占用降低到最小。例如,可以使用压缩算法来压缩纹理和音频等资源,从而减少内存占用。 综上所述,进行应用性能优化时,需要从多个方面入手。除了 CPUGPU 和内存等方面,还需要考虑应用的网络请求、I/O 操作和 UI 渲染等方面。只有在全面考虑了这些因素之后,才能够有效地提高应用的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宗浩多捞

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值