我不清楚如何在Vulkan中并行处理不同线程上的工作。
为了开始发出vkCmd*s,您需要开始一个呈现传递。要开始呈现pass的调用需要对框架缓冲区的引用。但是,vkAcquireNextImageKHR()不能保证以循环方式返回图像索引。因此,在三重缓冲设置中,如果当前图像索引为0,则不能仅绑定framebuffer 1并开始对下一个帧发出抽签调用,因为下一个对vkAcquireNextImageKHR()的调用可能返回图像索引2。
什么是记录命令的正确方法,而不必事先指定要使用的框架缓冲区?
发布于 2018-02-05 15:59:44
您有一个或多个呈现通行证,您想要执行每帧。每一个都有一个或多个子通道,你想把工作倾注到其中。因此,主呈现线程将为这些子传递生成一个或多个辅助命令缓冲区,并将二级CBs序列传递给提交线程。
提交线程将创建呈现的主CB。它开始/结束呈现传递,并在每个子传递中执行为该特定子传递在呈现线程上创建的辅助CB(s)。
所以每个线程都在创建自己的命令缓冲区。提交线程是处理VkFramebuffer对象的线程,因为它开始呈现传递。它也是获取交换链图像等等的对象。呈现线程是使辅助CBs执行所有实际工作的线程。
是的,你仍然会在提交线程上做一些CB构建,但是它应该是相当简约的整体。这还有助于从呈现线程中抽象出呈现目标的细节,以便可以将处理交换链的代码本地化到提交线程。这给了你更多的灵活性。
例如,如果您想要三重缓冲区,而swapchain实际上不允许这样做,那么提交线程可以创建它自己的额外图像,然后从它的内部映像复制到真正的空白链中。不需要干扰呈现线程的代码就可以做到这一点。
发布于 2018-02-05 05:59:05
可以使用多个线程来使用辅助命令缓冲区为相同的呈现传递生成绘制命令。你可以并行地为同一帧中的不同渲染传递生成工作--只有最后一次传递(通常是后处理传递)取决于特定的交换链图像、所有阴影传递、gbuffer/阴影/照明传递,除了最后一次后处理传递之外,其他所有处理传递都不需要。它不是必需的,但在您准备好开始生成最后的渲染传递之前,不要调用vkAcquireNextImageKHR通常是一个好主意,因为您已经生成了许多之前的传递。
发布于 2018-02-05 07:42:12
首先,要明确:
为了开始发出vkCmd*s,您需要开始一个呈现传递。
这不一定是真的。在命令缓冲区中,您可以记录多个不同的命令,所有这些命令都以vkCmd开头。这些命令中只有一些需要记录在呈现传递中--那些与绘图相关的命令。有一些命令不能在呈现传递中调用(例如,分派计算着色器)。但这只是解决问题的一个附带注意事项。
下一件事-提到三重缓冲。在Vulkan中,图像的显示方式取决于支持的当前模式。不同的硬件供应商,甚至不同的驱动程序版本,可能提供不同的当前模式,因此,在一种硬件上,您可能会得到与三重缓冲(邮箱)最相似的当前模式,但在另一种硬件上,您可能无法得到它。现在模式会影响表示引擎允许您从交换链中获取图像的方式,然后在屏幕上显示它们。但是,正如您所指出的,您不能依赖返回图像的顺序,因此您不应该将应用程序设计成在所有平台上都有相同行为的应用程序。
但要回答您的问题--最简单、最天真的方法是在帧的开头调用vkAcquireNextImageKHR(),记录使用它返回的图像的命令缓冲区,提交命令缓冲区并显示图像。您可以根据需要创建框架缓冲区,就在需要在命令缓冲区中使用它之前:创建一个框架缓冲区,它使用适当的图像(与vkAcquireNextImageKHR()函数返回的索引相关联),在命令缓冲区提交之后,当它们停止使用时,就销毁它。这种行为出现在Vulkan上:这里和这里。
更合适的方法是为所有可用的交换链映像准备框架缓冲区,并在帧期间采取适当的帧缓冲区。但是当你重新创建交换链时,你需要记住重新创建它们。
更高级的场景将推迟到真正需要时才进行交换链的收购。vkAcquireNextImageKHR()函数调用可能会阻塞应用程序(直到图像可用),因此在准备帧时应该尽可能晚地调用它。这就是为什么您应该记录不需要首先引用交换链图像的命令缓冲区(例如,那些在延迟阴影算法中将几何图形呈现为G-缓冲区的图像)。之后,当您想要在屏幕上显示图像(例如,一些后处理技术)时,只需采用上面描述的方法:获取图像,准备适当的命令缓冲区并显示图像。
您还可以使用预记录命令缓冲区来引用特定的交换链图像.如果您知道您的映像源总是相同的(就像前面提到的G-缓冲区),那么您可以拥有一组命令缓冲区,这些命令缓冲区总是从这些数据执行一些后处理/复制操作到所有的swapchain映像--每个swap链映像只有一个命令缓冲区。然后,在帧期间,如果设置了所有数据,则获取图像,检查哪个预录制的命令缓冲区是合适的,并提交与获取的图像相关的命令缓冲区。
实现您想要的东西有多种方法,所有这些都取决于许多因素--性能、平台、您想要达到的特定目标、您在应用程序中执行的操作类型、您实现的同步机制以及许多其他事情。你得找出什么最适合你。但是最后,如果要在屏幕上显示图像,则需要在命令缓冲区中引用一个交换链图像。我建议先从最简单的选项开始,然后,当您习惯它时,您可以改进您的实现,以获得更高的性能、灵活性、更容易的代码维护等等。
https://stackoverflow.com/questions/48615465
复制相似问题