问题描述
当我的场景更新时(例如引入了新模型),我使用函数 tempBuffer
将我的绘图命令缓冲区重新记录到新的命令缓冲区 (buildCommandBuffers
) 中。
我有一个 drawCmdBuffers
数组,用于主绘制例程。
让问题稍微复杂一点,我的 buildCommandBuffers
函数可能会从单独线程中的计时器调用,因此在发生此更新时渲染函数可能仍在循环。这是因为我的场景更新可能需要一段时间,我需要在创建命令缓冲区时锁定场景内存(这是一个单独的问题......但添加的每个网格都会触发场景更新,我需要能够缓冲这些更新).
我为每个命令缓冲区设置了一个栅栏,所以一旦我记录到我的“tempBuffer”中,我就会执行以下操作:
VK_CHECK_RESULT(vkEndCommandBuffer(tempBuffers[i]));
// wait for this command buffer to finish (we might be re-recording)
if (imagesInFlight[_image_index] != VK_NULL_HANDLE)
{
vkWaitForFences(device,1,&imagesInFlight[_image_index],VK_TRUE,UINT64_MAX);
}
// destroy in use command buffer
vkFreeCommandBuffers(device,cmdPool,&drawCmdBuffers[i]);
drawCmdBuffers[i] = tempBuffers[i];
这样安全吗?或者我可以做些什么来停止对 drawCmdBuffers[i]
的访问?
解决方法
看起来您需要 CPU-CPU 同步(通常是互斥锁)来访问 imagesInFlight[]
数组和 drawCommandBuffers[]
或其中的单个元素。否则,您可能正在等待最近帧的栅栏,而另一个线程正在为下一帧提交命令缓冲区——在这种情况下,即使您的等待完成,GPU 仍将使用命令缓冲区。
假设您确实需要重用命令缓冲区而不是每帧重新记录它们,一种方法是让 buildCommandBuffers
线程只构建对 drawCmdBuffers
的更改列表。类似的东西:
渲染线程:
for each frame:
acquire mutex for command buffer edit list
for (i,cmdbuf) in command buffer edit list:
push drawCmdBuffers[i] and most recent frame fence to a deferred-destroy queue
drawCmdBuffers[i] = cmdbuf;
clear edit list
release mutex
submit render commands for frame,using drawCmdBuffers
更新线程:
on_timer:
acquire mutex for command buffer edit list
while fence at front of deferred-destroy queue has signaled:
free command buffer at front of queue
pop queue
release mutex
for each command buffer that needs to be replaced:
record command buffer
acquire mutex for command buffer edit list
append (cmdbuf_index,cmdbuf) to edit list
release mutex
这样只有渲染线程直接访问drawCmdBuffers
,所以不需要保护。您只有一个从定时器线程到渲染线程的编辑队列,以及一个命令缓冲区队列,用于从渲染线程到定时器线程(或实际在栅栏上等待的其他线程,而不仅仅是轮询)他们在每个计时器上)。在任何给定时刻(除了短暂的互斥锁被持有时),命令缓冲区句柄仅在这些列表中的一个中。