【问题标题】:What is the relation between render passes, command buffers and clearing of attachments in vulkan?vulkan 中的渲染通道、命令缓冲区和清除附件之间的关系是什么?
【发布时间】:2018-02-01 00:18:37
【问题描述】:

我目前正在学习 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的误解?当已经运行一个渲染通道时,它实际上不是开始一个新的渲染通道吗?!

感谢您的帮助。

【问题讨论】:

    标签: renderer vulkan


    【解决方案1】:

    命令缓冲区负责存储稍后提交到队列并由硬件处理的命令。这是在 Vulkan 中执行操作的唯一方法 - 记录它们然后提交。但重要的是每个命令缓冲区完全独立于所有其他命令缓冲区。如果要执行特定作业,则需要将设置适当状态的所有必要命令记录到命令缓冲区中。如果您想在另一个命令缓冲区中执行类似的工作,您需要在另一个命令缓冲区中记录相同的命令集,因为命令缓冲区之间没有状态共享。他们都是独立的。 (有一些例外,但它们与本次讨论无关,因为它们只涉及辅助命令缓冲区)。

    接下来,在 Vulkan 中,渲染只能发生在渲染通道内。渲染通道是对步骤(称为子通道)的一般定义,绘制命令被划分为这些绘制命令(附件)所需的渲染资源(以及它们之间的关系)。但这只是描述,元数据。您定义如何使用这些附件(作为颜色附件、作为深度附件、作为输入附件)以及它们在每个子通道中的布局。您还可以在渲染过程(加载操作)之前和渲染过程之后(存储操作)定义每个附件的处理方式。

    现在用于这些附件的实际资源是通过帧缓冲区定义的。通过这种方式,您可以对各种图像集(通过使用各种但兼容的帧缓冲区)执行类似的渲染操作,而无需重新创建渲染通道。并且在您开始渲染过程时定义了在渲染期间应该使用哪个帧缓冲区。

    现在,当我们结合上述信息、渲染通道和命令缓冲区时,我们得到:每个命令缓冲区都是独立的,因此渲染必须在单个命令缓冲区(不包括辅助命令缓冲区)期间开始和结束。所以这也意味着您需要在单个命令缓冲区中开始和结束渲染通道(当然您也可以在单个命令缓冲区中开始和结束多个渲染通道)。

    这是否意味着每个提交的命令缓冲区都会开始一个新的 renderpass 等清除附件?

    如果您想要一个仅通过执行计算着色器来执行数学计算的命令缓冲区,那么您不需要渲染通道。所以这样的命令缓冲区不需要开始和结束任何渲染过程,也不需要清除任何附件。但是,如果您想在命令缓冲区中渲染,那么是的,每个这样的命令缓冲区都必须开始(和结束)一个渲染过程。如果渲染涉及到清除,那么每个需要执行该操作的命令缓冲区也需要清除附件。

    还是对vkCmdBeginRenderPass的误解?难道不是 当已经运行了一个渲染通道时,实际上开始一个新的渲染通道?!

    vkCmdBeginRenderPass() 开始一个新的渲染通道,是的,但是在单个命令缓冲区中您无法开始另一个渲染通道,直到前一个渲染通道结束。您必须显式启动渲染通道并结束它。只有在那之后你才能开始另一个渲染通道(在同一个命令缓冲区中)。

    至于清除,它们也是在渲染通道开始时定义的,它允许您清除具有不同颜色的附件。这样您就不必每次要更改“背景”颜色时都创建单独的渲染通道。

    还有一件关于附件清除的事情:除非真的有必要,否则使用渲染通道清除 (LOAD_OP_CLEAR) 而不是显式清除 (vkCmdClear()),因为它们可能会损害性能(大多数供应商建议使用渲染通道清除作为据我所知)。

    我希望这个希望能澄清这个话题。

    【讨论】:

    • 它确实澄清了一些事情,我不明白的是,我如何能够在没有其内部渲染通道清除颜色附件并基本上清除/删除任何内容的情况下为帧提交第二个命令缓冲区已经被之前的命令缓冲区渲染了。
    • 通过在单个命令缓冲区中记录多个渲染通道(首先将清除资源,其他不会或将仅清除其中一些)。或者通过创建另一个根本不清除附件的渲染通道并为每个附件提供适当的帧缓冲区。或者通过创建对不同图像集进行操作的渲染通道 - 在第一个命令缓冲区中清除附件并渲染到它们;在以下命令缓冲区中您从以前的命令缓冲区中读取附件并使用其他图像作为附件(因此它们也可以被清除)。
    • “所以渲染必须在单个命令缓冲区(不包括辅助命令缓冲区)中开始和结束”这是我问题的关键。我希望能够为场景的各个部分记录命令缓冲区,并在必要时提交它们(剔除后可见)并遇到清除问题。所以我必须在任何事情发生变化时重建一个大型命令缓冲区?或者使用辅助缓冲区。
    • 我没有过多地使用辅助命令缓冲区。但据我所知 - 辅助命令缓冲区(可能!)继承渲染通道状态(当您提供它时)。这意味着辅助命令缓冲区“知道”它是从哪个主命令缓冲区的子通道执行的(因此您不必在其中启动渲染通道)。但是,如果您想将场景的渲染划分为多个命令缓冲区,那么可以 - 通常您需要在每个缓冲区中开始和结束渲染通道。因此,您可能需要一个命令缓冲区来清除附件和其他不这样做的缓冲区。
    【解决方案2】:

    回答您的问题: 通常,在渲染某些内容之前,您会在帧开始时清除。 beginRenderpass 只能由主 commandbuffer 调用,辅助 commandbuffer 不能调用此调用。 基本上,您正在主命令缓冲区中启动一个渲染通道实例(只有您可以提交到队列的命令缓冲区), 这就是您将在每一帧上执行的操作。

    但您可以通过调用清除渲染通道实例内的一个或多个颜色和深度/模板附件区域 vkCmdClearAttachments 无论是 LOAD_OP_CLEAR / LOAD_OP_DONT_CARE, 或者如果你想在渲染通道之外使用 vkCmdClearColor/DepthStencilImage。 这可以由主命令缓冲区或辅助命令缓冲区调用。

    提示:使用 LOAD_OP_DONT_CARE 可能会在某些驱动程序上进行优化,如果您确定会覆盖前一帧写入的整个屏幕。 因此驱动程序不必为当前的渲染通道从演示缓冲区加载/复制内存来清除它。

    您可以在辅助命令缓冲区中使用 vkCmdClearAttachment 命令来清除任何附件。 但是你不能自己提交它们,它必须放在主命令缓冲区中。

    这是否意味着每个提交的命令缓冲区都会启动一个新的渲染通道,从而清除附件? 是对 vkCmdBeginRenderPass 的误解吗? 是的,每个提交命令缓冲区都会启动渲染通道并清除 fbo 附件。

    当已经运行了一个渲染通道时,它实际上不是开始一个新的渲染通道吗? Renderpass 包含帧缓冲区的执行顺序。它有状态。 状态在每一帧上被重用。您可以使用具有相同 fbo 的另一个渲染通道(不同状态)。 所以第一个渲染通道可以清除它,而第二个渲染通道在帧开始时不会清除。

    您不能在渲染通道实例中调用另一个渲染通道。 您在下面看到的内容无效

    Commandbuffer.beginRenderpass(renderpass1, fbo, ClearValues);
    Commandbuffer.beginRenderpass(renderpass2, fbo, ClearValues);// ERROR 
    Commandbuffer.end;
    

    您必须在开始第二个渲染过程之前结束 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 个渲染通道。 首先:使用 renderpass1 将场景渲染到附件 1。 第二:从附件 1 中读取并进行垂直模糊,然后使用 renderpass2 写入附件 2。 第三:从附件 2 中读取并进行水平模糊并使用 renderpass3 写入交换链图像。 (注意:对于这个特殊的技术,我们不能使用多个子通道,这就是为什么我对同一个 fbo 使用 3 个渲染通道。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-19
      • 2019-10-14
      • 1970-01-01
      • 2013-10-28
      相关资源
      最近更新 更多