我目前正在学习vulkan并遇到上述问题,我似乎无法通过阅读规范来回答。
查看规范和代码示例时,它始终是相同的简化工作流程:
begin commandbuffer
begin renderpass
bind stuff (pipeline, buffers, descriptor sets)
draw
end renderpass
end commandbuffer
create_submit_info
submit_to_graphics_queue
现在我不清楚的第一件事是何时清除附件。如果我使用LOAD_OP_CLEAR创建附件,则必须为VkRenderPassBeginInfo
提供清除值,但每个命令缓冲区都包含vkBeginRenderpass
。
那是否意味着每个提交的命令缓冲区都会启动一个新的renderpass,从而清除附件?这听起来不对。
如果我指定LOAD_OP_DONT_CARE,那么我必须使用vkCmdClear
这类请求单独的命令缓冲区来清除附件。哪个也不对。
那么有人可以为我清除命令缓冲区和渲染通道之间的关系吗?
或者是对vkCmdBeginRenderPass
的误解?当有一个已经运行时,它是否真的没有开始新的渲染过程?!
感谢您的帮助。
答案 0 :(得分:1)
命令缓冲区负责存储稍后提交给队列并由硬件处理的命令。这是在Vulkan中执行操作的唯一方法 - 记录它们然后提交。但重要的是每个命令缓冲区完全独立于所有其他命令缓冲区。如果要执行特定作业,则需要将设置适当状态的所有必要命令记录到命令缓冲区中。如果要在另一个命令缓冲区中执行类似的作业,则需要在另一个命令缓冲区中记录同一组命令,因为命令缓冲区之间没有状态共享。他们都是独立的。 (有一些例外,但它们与此讨论无关,因为它们只涉及辅助命令缓冲区)。
接下来,在Vulkan渲染中,只能在渲染过程中进行渲染。渲染过程是步骤(称为子通道)的一般定义,绘图命令被分为这些绘图命令(附件)所需的渲染资源(以及它们之间的关系)。但这只是描述,元数据。您可以定义如何使用这些附件(作为颜色附件,深度附件,作为输入附件)以及每个子通道中的布局。您还可以在渲染过程(加载操作)之前和渲染过程(存储操作)之后定义如何处理每个附件。
现在,用于这些附件的实际资源是通过framebuffers定义的。这样您可以在各种图像集上执行类似的渲染操作(通过使用各种但兼容的帧缓冲区),而无需重新创建渲染过程。在渲染渲染过程中定义渲染期间应使用哪个帧缓冲区。
现在,当我们结合上述信息,渲染传递和命令缓冲区时,我们得到:每个命令缓冲区都是独立的,因此渲染必须在单个命令缓冲区(不包括辅助命令缓冲区)期间开始和结束。这也意味着您需要在单个命令缓冲区内开始和结束渲染过程(当然,您也可以在单个命令缓冲区中开始和结束多个渲染过程)。
这是否意味着每个提交的命令缓冲区都会启动一个新的 renderpass,所以清除附件?
如果您想要一个仅通过执行计算着色器执行数学计算的命令缓冲区,那么您不需要渲染过程。因此,这样的命令缓冲区不需要开始和结束任何渲染过程,并且它不需要清除任何附件。但是如果你想在命令缓冲区中渲染,那么是的,每个这样的命令缓冲区必须启动(并结束)渲染通道。如果渲染涉及清除,则需要执行此类操作的每个命令缓冲区也需要清除附件。
或者是对vkCmdBeginRenderPass的误解?不是吗 实际上有一个正在运行的时候会开始一个新的渲染过程吗?!
vkCmdBeginRenderPass()
启动一个新的渲染过程,是的,但在单个命令缓冲区中,在上一个渲染过程结束之前,您无法启动另一个渲染过程。您必须显式启动渲染过程并结束它。只有在那之后你才能开始另一个渲染过程(在同一个命令缓冲区中)。
对于清除,它们也在渲染过程开始时定义,允许您清除不同颜色的附件。这样,每次您想要更改"背景"时,您都不必创建单独的渲染通道。颜色。
还有一个关于附件清除的事情:除非确实有必要,否则使用渲染过程清除(LOAD_OP_CLEAR
)而不是显式清除(vkCmdClear()
),因为它们可能会损害性能(大多数建议使用渲染过程清除)据我所知,供应商的数量。)
我希望这个希望能够澄清这个话题。
答案 1 :(得分:0)
回答你的问题: Normaly你在框架开始时,在渲染之前就清楚了。 beginRenderpass只能由主命令缓冲区调用,辅助命令缓冲区不能调用此调用。 基本上你是在主命令缓冲区中启动一个renderpass实例(只有你可以提交给队列的commandbuffer), 这就是你将在每一帧上做的事情。
但您可以通过调用清除渲染过程实例中的一个或多个颜色和深度/模板附件区域 vkCmdClearAttachments,无论是否为LOAD_OP_CLEAR / LOAD_OP_DONT_CARE, 或者如果你想在renderpass旁边使用vkCmdClearColor / DepthStencilImage。 这可以由主命令缓冲区或辅助命令缓冲区调用。
提示:如果您确定要覆盖前一帧写入的整个屏幕,则可以在某些驱动程序上优化使用LOAD_OP_DONT_CARE。 所以驱动程序不必从当前renderpass的presenation缓冲区加载/复制内存以清除它。
您可以在辅助comandbuffer中使用vkCmdClearAttachment命令清除任何附件。 但是你不能自己提交它们,它必须放在主命令缓冲区中。
这是否意味着每个提交的命令缓冲区都会启动一个新的renderpass,从而清除附件? 这是对vkCmdBeginRenderPass的误解吗? 是的每个提交命令缓冲区启动renderpass并清除fbo附件。
当已经有一个正在运行时,它是否真的没有开始新的渲染过程? Renderpass包含帧缓冲区的执行顺序。它有州。 状态在每个帧上重复使用。你可以使用另一个具有相同fbo的renderpass(不同的状态)。 所以第一个渲染通道可以清除它,第二个渲染通道不会在帧的开头清除。
你不能在renderpass实例中调用另一个renderpass。 您在下面看到的内容无效
Commandbuffer.beginRenderpass(renderpass1, fbo, ClearValues);
Commandbuffer.beginRenderpass(renderpass2, fbo, ClearValues);// ERROR
Commandbuffer.end;
在开始第二个renderpass之前,你必须结束renderpass1实例。 应该是这样的
Commandbuffer.beginRenderpass(renderpass1, fbo, ClearValues);
// draw scene
Commandbuffer.end;// renderpass is ended
Commandbuffer.beginRenderpass(renderpass2, fbo, ClearValues);
// draw full screen quad
Commandbuffer.end;
Commandbuffer.beginRenderpass(renderpass3, fbo, ClearValues);
// draw full screen quad
Commandbuffer.end;
让我们说在上面的例子中,fbo有3个附件。我们在这里使用3个renderpass。 第一步:使用renderpass1将场景渲染到附件1。 第二步:从附件1读取并执行垂直模糊并使用renderpass2写入附件2。 第三步:从附件2读取并进行Horinzontal模糊并使用renderpass3写入交换链图像。 (注意:对于这个特殊的技术,我们不能使用多个子通道,这就是为什么我在同一个fbo上使用3个渲染通道。)