graphics - 在 Vulkan 中使用多线程渲染渲染到不同的帧缓冲区
问题描述
我试图重现与此视频类似的结果:https ://www.youtube.com/watch?v=21UsMuFTN0k具体来说,我想将整个场景渲染为不同的纹理,并将纹理放在 UI 中像这个视频截图:
视频的作者正在使用 OpenGL 来执行此操作,而我试图在 Vulkan 中实现它。但是,由于我当前的程序使用第三个附件来启用 MSAA 并使用辅助命令缓冲区渲染整个场景,因此我很难将视频中执行此操作的方式转换为 Vulkan。我想我可能不仅需要更多的帧缓冲区,还需要多个渲染通道。简而言之,到目前为止,这是我尝试过的:
- 开始第一个渲染通道,将渲染通道开始信息设置为较小的渲染区域、屏幕外渲染通道和单独的帧缓冲区。
- 将屏幕外渲染通道和帧缓冲区传递给继承信息,并将其传递给辅助命令缓冲区以进行绘制。
- 结束第一个渲染过程。
- 开始第二个渲染通道,将渲染通道开始信息设置为屏幕的实际大小、主渲染通道和主帧缓冲区。
- 将第二个渲染通道和帧缓冲区传递给继承信息,并将其传递给辅助命令缓冲区以进行绘图。
- 做
vkCmdExecuteCommands
。 - 结束第二个渲染过程。
- 结束命令缓冲区。
尽管如此,当程序执行时,验证层显示:
vkCmdExecuteCommands(): Cannot duplicate VkCommandBuffer 0x1c26226d2e8[] in pCommandBuffers without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. The Vulkan spec states: If any element of pCommandBuffers was not recorded with the VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT flag, it
must not appear more than once in pCommandBuffers
这是否意味着我必须VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT
为所有辅助命令缓冲区设置?或者有其他方法可以纠正吗?因为据我所知,设置VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT
有性能成本。此外,如果我尝试vkExecuteCommands
在每个渲染通道中执行此操作,验证层将显示命令缓冲区已被破坏。
我想知道在 Vulkan 中重现类似结果的正确方法是什么,以及我是否必须将它们分开以便我必须vkQueueSubmit
多次执行。
解决方案
您正在尝试在单个 CommandBuffer 中使用不同的帧缓冲区执行两个 RenderPass。
渲染通道执行
在 Graphics Queue 中执行 RenderPass 可以是无序的,即)不保证 RenderPass 将根据提交顺序执行。因为,您在同一个命令缓冲区中记录多遍,这可能是一个问题
使用信号量进行同步
将 First RenderPass 和 Second RenderPass 记录在不同的 Command Buffers 中,并在提交到队列时使用 Semaphores 进行同步。
使用 Semaphore 在 vkQueueSubmit 中为First RenderPass发出信号。当您提交第二个 RenderPass时,请使用等待槽中的信号量。
检查VKQueueSubmit中的VKSubmitInfo。这用于队列中的内部同步。
图像布局过渡
您还必须确保您编写和读取的纹理在适当的 RenderPasses 中位于正确的布局中。
- 首先 RenderPass,纹理必须在COLOR_ATTACHMENT_OPTIMAL
- 第二个 RenderPass,纹理必须在SHADER_READ_ONLY_OPTIMAL
您可以使用 ImageBarrier 或制作第一个渲染通道输出以将附件布局转换为 Read_Only,从而尽早做好准备。
一般说明
- 使用 CommandBuffer 记录 First Pass,将 Texture 的 Final ImageLayout 更改为 SHADER_READ_ONLY_OPTIMAL(如果不使用 ImageBarrier)
- 使用 CommandBuffer 记录第二遍
- 使用等待信号量提交First Pass
- 使用信号 Semaphore提交Second Pass
如果使用 ImageBarrier,则需要一个信号量和一个命令缓冲区才能插入到第一和第二通道的中间。
Command_Buffer_Simultaneous_Use_Bit
当您需要存储一些需要多次提交到不同队列或记录到不同主缓冲区的命令时,使用同步位。
这通常在辅助缓冲区中用于存储少量命令(可能是许多进程中的通用过程)并根据需要在主缓冲区中记录。
在你的情况下,它是不需要的。
推荐阅读
- pandas - 在pandas Python中添加迄今为止的小数年数
- python - Tensorflow 2:使用自定义层和 tf.map_fn 构建估计器
- mysql - 向列添加索引会提高 SQL 中的选择查询(没有 where)性能吗?
- html - css 将一个段落放在顶部,另一个放在按钮上
- mysql - MySQL:从 JDBC 中选择 INTO OUTFILE 的状态
- apache-flink - Flink 有状态函数,使用 python SDK 进行异步调用
- angular - 如何正确使用exhaustMap - 如何在发送另一个请求之前等待服务调用返回
- c++ - 对 unique_ptr 使用 fortify 静态代码分析器时的内存泄漏
- python - 如何通过在python的二维数组中使用if技术来找到最大值、最小值和平均值
- swift - SwiftUI:ListItem 手势