vulkan 中渲染通道、命令缓冲区和附件清除之间的关系是什么?
What is the relation between render passes, command buffers and clearing of attachments in vulkan?
我目前正在学习 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
。
那么这是否意味着每个提交的命令缓冲区都会启动一个新的渲染通道并因此清除附件?这听起来不对。
如果我指定 LOAD_OP_DONT_CARE,那么我必须使用 vkCmdClear
,这需要一个单独的命令缓冲区来清除附件。这也不对。
所以有人可以为我澄清命令缓冲区和渲染过程之间的关系吗?
还是对vkCmdBeginRenderPass
的误解?当已经有一个 运行 时,它实际上不会开始一个新的渲染通道吗?!
感谢您的帮助。
命令缓冲区负责存储稍后提交到队列并由硬件处理的命令。这是在 Vulkan 中执行操作的唯一方法 - 记录它们然后提交。但重要的是每个命令缓冲区都完全独立于所有其他命令缓冲区。如果你想执行一个特定的工作,你需要将所有设置适当状态的必要命令记录到命令缓冲区中。如果你想在另一个命令缓冲区中执行类似的工作,你需要在另一个命令缓冲区中记录相同的命令集,因为命令缓冲区之间没有状态共享。他们都是独立的。 (有一些例外,但它们与本次讨论无关,因为它们仅涉及辅助命令缓冲区)。
接下来,在 Vulkan 中,渲染只能发生在渲染过程中。渲染通道是对绘制命令划分的步骤(称为子通道)以及这些绘制命令所需的渲染资源(以及它们之间的关系)的一般定义(附件)。但这只是描述,元数据。您定义这些附件的使用方式(作为颜色附件、作为深度附件、作为输入附件)以及它们在每个子通道中的布局。您还可以定义在渲染过程之前(加载操作)和渲染过程之后(存储操作)如何处理每个附件。
现在用于这些附件的实际资源是通过帧缓冲区定义的。这样您就可以对各种图像集执行类似的渲染操作(通过使用各种但兼容的帧缓冲区),而无需重新创建渲染通道。渲染过程中应使用哪个帧缓冲区是在您开始渲染过程时定义的。
现在,当我们结合上述信息、渲染通道和命令缓冲区时,我们得到:每个命令缓冲区都是独立的,因此渲染必须在单个命令缓冲区(不包括辅助命令缓冲区)期间开始和结束。所以这也意味着您需要在单个命令缓冲区中开始和结束渲染过程(当然您也可以在单个命令缓冲区中开始和结束多个渲染过程)。
So does that mean that every submitted command buffer starts a new
renderpass and so clears the attachments?
如果您想要一个仅通过执行计算着色器来执行数学计算的命令缓冲区,那么您不需要渲染通道。所以这样的命令缓冲区不需要开始和结束任何渲染过程,也不需要清除任何附件。但是如果你想在命令缓冲区中渲染,那么是的,每个这样的命令缓冲区都必须开始(和结束)一个渲染过程。如果渲染涉及到清除,那么每个需要执行该操作的命令缓冲区也需要清除附件。
Or is it a misunderstanding of vkCmdBeginRenderPass? Does it not
actually begin a new render pass when there is one running already?!
vkCmdBeginRenderPass()
启动一个新的渲染通道,是的,但是在单个命令缓冲区中您不能启动另一个渲染通道,直到上一个渲染通道结束。您必须明确地开始渲染过程并结束它。只有在那之后你才能开始另一个渲染过程(在同一个命令缓冲区中)。
至于清除,它们也在渲染通道开始时定义,这允许您清除具有不同颜色的附件。这样你就不必每次都创建一个单独的渲染通道你想改变"background"颜色。
关于附件清除的另一件事:除非确实有必要,否则使用渲染通道清除 (LOAD_OP_CLEAR
) 而不是显式清除 (vkCmdClear()
),因为它们可能会损害性能(推荐渲染通道清除据我所知,大多数供应商都是如此。
我希望这个希望能澄清这个话题。
回答您的问题:
通常情况下,在渲染某些内容之前,您会在帧开始时清除。
beginRenderpass 只能由主命令缓冲区调用,辅助命令缓冲区不得调用此调用。
基本上你在主命令缓冲区中启动一个 renderpass 实例(只有你可以提交到队列的命令缓冲区),
这就是您将在每一帧上执行的操作。
但是您可以清除渲染过程实例中的一个或多个颜色区域和 depth/stencil 附件,方法是调用
vkCmdClearAttachments 不管是LOAD_OP_CLEAR / LOAD_OP_DONT_CARE,
或者如果你想在你使用 vkCmdClearColor/DepthStencilImage 的 renderpass 之外进行。
这可以由主命令缓冲区或辅助命令缓冲区调用。
提示:使用LOAD_OP_DONT_CARE可能会在某些驱动程序上进行优化,如果您确定会覆盖前一帧写入的整个屏幕。
因此驱动程序不必 load/copy 当前渲染通道的演示缓冲区中的内存来清除它。
您可以在辅助命令缓冲区中使用 vkCmdClearAttachment 命令清除任何附件。
但是不能单独提交,必须放在primary commandbuffer里面。
那么这是否意味着每个提交的命令缓冲区都会启动一个新的 renderpass 并因此清除附件?
是对vkCmdBeginRenderPass的误解吗?
是的,每次提交命令缓冲区都会启动 renderpass 并清除 fbo 附件。
当已经有一个 运行 时,它实际上不会开始一个新的渲染过程吗?
Renderpass 包含帧缓冲区的执行顺序。它有状态。
这些状态在每一帧上重复使用。您可以使用具有相同 fbo 的另一个 renderpass(不同状态)。
所以第一个 renderpass 可以清除它,第二个 renderpass 在帧开始时不清除。
您不能在 renderpass 实例中调用另一个 renderpass。
您在下面看到的内容无效
Commandbuffer.beginRenderpass(renderpass1, fbo, ClearValues);
Commandbuffer.beginRenderpass(renderpass2, fbo, ClearValues);// ERROR
Commandbuffer.end;
您必须在开始第二个渲染通道之前结束渲染通道 1 实例。
应该是这样
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 个渲染通道。
首先:使用 renderpass1 将场景渲染到附件 1。
第二:从附件 1 中读取并进行垂直模糊,然后使用 renderpass2 写入附件 2。
第三:从附件 2 中读取并进行水平模糊并使用 renderpass3 写入交换链图像。
(注意:对于这个特殊的技术,我们不能使用多个子通道,这就是为什么我对同一个 fbo 使用 3 个渲染通道。)
我目前正在学习 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
。
那么这是否意味着每个提交的命令缓冲区都会启动一个新的渲染通道并因此清除附件?这听起来不对。
如果我指定 LOAD_OP_DONT_CARE,那么我必须使用 vkCmdClear
,这需要一个单独的命令缓冲区来清除附件。这也不对。
所以有人可以为我澄清命令缓冲区和渲染过程之间的关系吗?
还是对vkCmdBeginRenderPass
的误解?当已经有一个 运行 时,它实际上不会开始一个新的渲染通道吗?!
感谢您的帮助。
命令缓冲区负责存储稍后提交到队列并由硬件处理的命令。这是在 Vulkan 中执行操作的唯一方法 - 记录它们然后提交。但重要的是每个命令缓冲区都完全独立于所有其他命令缓冲区。如果你想执行一个特定的工作,你需要将所有设置适当状态的必要命令记录到命令缓冲区中。如果你想在另一个命令缓冲区中执行类似的工作,你需要在另一个命令缓冲区中记录相同的命令集,因为命令缓冲区之间没有状态共享。他们都是独立的。 (有一些例外,但它们与本次讨论无关,因为它们仅涉及辅助命令缓冲区)。
接下来,在 Vulkan 中,渲染只能发生在渲染过程中。渲染通道是对绘制命令划分的步骤(称为子通道)以及这些绘制命令所需的渲染资源(以及它们之间的关系)的一般定义(附件)。但这只是描述,元数据。您定义这些附件的使用方式(作为颜色附件、作为深度附件、作为输入附件)以及它们在每个子通道中的布局。您还可以定义在渲染过程之前(加载操作)和渲染过程之后(存储操作)如何处理每个附件。
现在用于这些附件的实际资源是通过帧缓冲区定义的。这样您就可以对各种图像集执行类似的渲染操作(通过使用各种但兼容的帧缓冲区),而无需重新创建渲染通道。渲染过程中应使用哪个帧缓冲区是在您开始渲染过程时定义的。
现在,当我们结合上述信息、渲染通道和命令缓冲区时,我们得到:每个命令缓冲区都是独立的,因此渲染必须在单个命令缓冲区(不包括辅助命令缓冲区)期间开始和结束。所以这也意味着您需要在单个命令缓冲区中开始和结束渲染过程(当然您也可以在单个命令缓冲区中开始和结束多个渲染过程)。
So does that mean that every submitted command buffer starts a new renderpass and so clears the attachments?
如果您想要一个仅通过执行计算着色器来执行数学计算的命令缓冲区,那么您不需要渲染通道。所以这样的命令缓冲区不需要开始和结束任何渲染过程,也不需要清除任何附件。但是如果你想在命令缓冲区中渲染,那么是的,每个这样的命令缓冲区都必须开始(和结束)一个渲染过程。如果渲染涉及到清除,那么每个需要执行该操作的命令缓冲区也需要清除附件。
Or is it a misunderstanding of vkCmdBeginRenderPass? Does it not actually begin a new render pass when there is one running already?!
vkCmdBeginRenderPass()
启动一个新的渲染通道,是的,但是在单个命令缓冲区中您不能启动另一个渲染通道,直到上一个渲染通道结束。您必须明确地开始渲染过程并结束它。只有在那之后你才能开始另一个渲染过程(在同一个命令缓冲区中)。
至于清除,它们也在渲染通道开始时定义,这允许您清除具有不同颜色的附件。这样你就不必每次都创建一个单独的渲染通道你想改变"background"颜色。
关于附件清除的另一件事:除非确实有必要,否则使用渲染通道清除 (LOAD_OP_CLEAR
) 而不是显式清除 (vkCmdClear()
),因为它们可能会损害性能(推荐渲染通道清除据我所知,大多数供应商都是如此。
我希望这个希望能澄清这个话题。
回答您的问题: 通常情况下,在渲染某些内容之前,您会在帧开始时清除。 beginRenderpass 只能由主命令缓冲区调用,辅助命令缓冲区不得调用此调用。 基本上你在主命令缓冲区中启动一个 renderpass 实例(只有你可以提交到队列的命令缓冲区), 这就是您将在每一帧上执行的操作。
但是您可以清除渲染过程实例中的一个或多个颜色区域和 depth/stencil 附件,方法是调用 vkCmdClearAttachments 不管是LOAD_OP_CLEAR / LOAD_OP_DONT_CARE, 或者如果你想在你使用 vkCmdClearColor/DepthStencilImage 的 renderpass 之外进行。 这可以由主命令缓冲区或辅助命令缓冲区调用。
提示:使用LOAD_OP_DONT_CARE可能会在某些驱动程序上进行优化,如果您确定会覆盖前一帧写入的整个屏幕。 因此驱动程序不必 load/copy 当前渲染通道的演示缓冲区中的内存来清除它。
您可以在辅助命令缓冲区中使用 vkCmdClearAttachment 命令清除任何附件。 但是不能单独提交,必须放在primary commandbuffer里面。
那么这是否意味着每个提交的命令缓冲区都会启动一个新的 renderpass 并因此清除附件? 是对vkCmdBeginRenderPass的误解吗? 是的,每次提交命令缓冲区都会启动 renderpass 并清除 fbo 附件。
当已经有一个 运行 时,它实际上不会开始一个新的渲染过程吗? Renderpass 包含帧缓冲区的执行顺序。它有状态。 这些状态在每一帧上重复使用。您可以使用具有相同 fbo 的另一个 renderpass(不同状态)。 所以第一个 renderpass 可以清除它,第二个 renderpass 在帧开始时不清除。
您不能在 renderpass 实例中调用另一个 renderpass。 您在下面看到的内容无效
Commandbuffer.beginRenderpass(renderpass1, fbo, ClearValues);
Commandbuffer.beginRenderpass(renderpass2, fbo, ClearValues);// ERROR
Commandbuffer.end;
您必须在开始第二个渲染通道之前结束渲染通道 1 实例。 应该是这样
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 个渲染通道。 首先:使用 renderpass1 将场景渲染到附件 1。 第二:从附件 1 中读取并进行垂直模糊,然后使用 renderpass2 写入附件 2。 第三:从附件 2 中读取并进行水平模糊并使用 renderpass3 写入交换链图像。 (注意:对于这个特殊的技术,我们不能使用多个子通道,这就是为什么我对同一个 fbo 使用 3 个渲染通道。)