Vulkan中为何仅顶点数据为空时重建缓冲会触发删除报错?
Vulkan网格删除时缓冲销毁异常问题分析
问题描述
实现场景网格删除功能时,运行时销毁vk::Buffer与vk::Memory出现以下异常:
- 当顶点数据为
nullptr时,重建缓冲触发错误:Cannot call vkFreeMemory on VkDeviceMemory that is currently in use by a command buffer - 当顶点数据不为空时无报错;仅在重建前调用
transferQueue.waitIdle()或device.waitIdle()才能消除顶点数据为nullptr时的错误
重建伪代码:
auto temp = m_Buffer; m_Buffer = Buffer(...); temp.Cleanup(...);
原因分析
两种场景的核心差异在于新缓冲构造过程中是否触发了队列空闲等待:
顶点数据非空的场景
此时VertexBuffer构造函数会执行完整的缓冲创建流程,包括调用CopyBuffer函数。而CopyBuffer中明确调用了transferQueue.waitIdle(),该函数会阻塞直到传输队列上所有已提交的命令执行完毕。这个等待操作间接确保了GPU上所有使用旧缓冲的命令(包括渲染队列中的绘制命令)已经执行完成,旧缓冲的内存不再被任何命令缓冲引用,因此后续调用temp.Cleanup()销毁内存不会触发错误。顶点数据为
nullptr的场景
此时VertexBuffer构造函数中m_Size为0,会跳过所有缓冲创建、数据拷贝的逻辑,自然也不会执行CopyBuffer中的transferQueue.waitIdle()。这意味着GPU上可能还有未完成的渲染命令在引用旧缓冲的内存,此时直接调用vkFreeMemory销毁内存,就会触发Vulkan的使用中内存无法释放的校验错误。
解决方案
无论顶点数据是否为空,在销毁旧缓冲前都需要确保GPU不再使用该内存:
- 直接方式:在
temp.Cleanup()前调用device.waitIdle(),等待设备所有队列的命令执行完毕(注意:该操作会阻塞CPU,性能敏感场景需谨慎使用) - 高效方式:使用**同步对象(Fence)**跟踪使用旧缓冲的最后一批命令,等待Fence触发后再执行销毁操作,避免全局等待带来的性能损耗
内容的提问来源于stack exchange,提问作者Robert Przikevicz
相关产品推荐
相关产品推荐

