Vulkan RenderPass

RenderPass从名字就可以看出是与渲染相关的,非渲染的任务则不需要使用RenderPass,例如:计算着色器就不需要RenderPass。

RenderPass渲染时用于设置FrameBuffer的格式,以及subpass。创建FrameBuffer和GraphicsPipeline时需要提供一个RenderPass对象。

typedef struct VkRenderPassCreateInfo {
    VkStructureType                   sType;
    const void*                       pNext;
    VkRenderPassCreateFlags           flags;
    uint32_t                          attachmentCount;
    const VkAttachmentDescription*    pAttachments;
    uint32_t                          subpassCount;
    const VkSubpassDescription*       pSubpasses;
    uint32_t                          dependencyCount;
    const VkSubpassDependency*        pDependencies;
} VkRenderPassCreateInfo;

RenderPass的概念和作用

RenderPass是Vulkan中一个重要的概念,它用于描述一系列的渲染操作,以及这些操作所涉及的资源和依赖关系。RenderPass的作用可以分为以下几个方面:

  • 设置FrameBuffer的格式
  • 设置渲染的subpass,主要是subpass的输入/输出 attachment
  • 设置各个subpass之间的同步
  • 转换attachment中Image的Layout

设置FrameBuffer格式

一个FrameBuffer可以有多个attachment,每个attachment会对应一个image。创建FrameBuffer时需要提供一个RenderPass,这个RenderPass中的attachment需要与FrameBuffer的attachment一一对应,且RenderPass中每个attachment设置的VkFormat需要和FrameBuffer中attachment对应的image格式一致。

设置渲染的subpass

typedef struct VkSubpassDescription {
    VkSubpassDescriptionFlags       flags;
    VkPipelineBindPoint             pipelineBindPoint;
    uint32_t                        inputAttachmentCount;
    const VkAttachmentReference*    pInputAttachments;
    uint32_t                        colorAttachmentCount;
    const VkAttachmentReference*    pColorAttachments;
    const VkAttachmentReference*    pResolveAttachments;
    const VkAttachmentReference*    pDepthStencilAttachment;
    uint32_t                        preserveAttachmentCount;
    const uint32_t*                 pPreserveAttachments;
} VkSubpassDescription;

一个RenderPass中可以有多个subpass,每个subpass可以设置输入的attachment、 输出的attachment、多重采样resolve的attachment

输入attachment

一个Renderpass中有多个subpass,后面的subpass需要用到前面subpass的渲染结果当作输入,这时就需要设置subpass的pInputAttachments,每个subpass可以设置多个输入。

输出attachment

每个subpass都必须有输出,可以设置多个颜色输出和一个深度模板输出。

多个颜色输出是用于MTR(Multiple Render Targets)技术,可以一次渲染输出到多个颜色attachment,例如延迟渲染就需要使用该技术用于同时输出颜色、位置、法线等。

深度模板缓存只有一个,也就是说如果同时用到深度测试和模板测试,需要Image同时包含深度和模板。

多重采样resolve的attachment

当使用多重采样时subpass可以在渲染完成后自动resolve,只需要设置pResolveAttachments,pResolveAttachments需要与pColorAttachments一一对应。

渲染时切换subpass

1. 在创建GraphicsPipeline时需要设置subpass的索引

2. vkCmdBeginRenderPass后渲染完一个subpass需要调用vkCmdNextSubpass切换到下一个subpass

subpass之间的同步和Layout转换

当有多个subpass时,需要控制subpass的执行顺序,让后面的subpass可以读取到输入attachment的渲染结果。

对于image使用前,需要根据用途转换到相应的Layout,例如:纹理用作Frame Buffer时Layout需要是COLOR_ATTACHMENT_OPTIMAL,纹理用作着色器采样时Layout需要是SHADER_READ_ONLY_OPTIMAL。

控制执行顺序和转换Layout需要通过SubpassDependency完成。

首先每个attachment有initialLayout和finalLayout,当前执行第一个subpass时,Vulkan会根据SubpassDependency插入一个vkCmdPipelineBarrier,这个Barrier会把Image从initialLayout转换到输出attachment设置的layout。如果没有SubpassDependency,Vulkan会帮我们生成一个默认的Barrier,这个默认的Barrier也同样会转换Layout,但是srcStageMask=TOP_OF_PIPE,这不是我们想要的,我们需要将srcStageMask=COLOR_ATTACHMENT_OUTPUT。

当最后一个subpass执行完后,Vulkan也会根据SubpassDependency插入一个vkCmdPipelineBarrier,这个Barrier会把Image从subpass的layout转换到finalLayout。如果没有SubpassDependency,Vulkan会帮我们生成一个默认的Barrier,这个默认的Barrier也同样会转换Layout,dstStageMask=BOTTOM_OF_PIPE。如果attachment的Image是来自SwapChain,渲染后是用于显示,这个默认生成的Barrier刚好是我们想要的,因为显示是通过semaphore同步的。如果不是来自SwapChain则需手动提供一个SubpassDependency。

在各个subpass之间我们也需要提供SubpassDependency,用来控制subpass的执行顺序,以及将输入attachment的Image Layout从COLOR_ATTACHMENT_OPTIMAL转换为SHADER_READ_ONLY_OPTIMAL。

Dynamic rendering

因为创建FrameBuffer和GraphicsPipeline时需要提供一个RenderPass对象,这导致RenderPass一旦有修改就需要重新创FrameBuffer和Pipeline。而且创建GraphicsPipeline时还需要设置一个subpass索引,使得Pipeline不能在不同的subpass之间复用。Vlkan的这种设计导致RenderPass和FrameBuffer、GraphicsPipeline之间的耦合太高,FrameBuffer和GraphicsPipeline不能复用,一点都不灵活。

在Vulkan 1.2版本中提供了一个扩展VK_KHR_dynamic_rendering,这个扩展用于支持Dynamic Rendering 可以渲染时不用创建Render Pass和FrameBuffer,让渲染更加灵活,可以更方便的复用Pipeline和代码。这个扩展不是强制要求实现的,所以并不是所有支持Vulkan1.2版本的显卡都支持。

虽然Dynamic Rendering可以不用创建RenderPass和FrameBuffer,但RenderPass做的事依然不能少,需要手动添加imageMemoryBarrier用于控制pass的执行顺序和Layout的转换。具体实现可以参考官方的例子:Dynamic Rendering

参考

https://github.com/SaschaWillems/Vulkan/tree/master/examples/inputattachments

https://github.com/SaschaWillems/Vulkan/blob/master/examples/dynamicrendering

https://github.com/KhronosGroup/Vulkan-Samples/blob/main/samples/extensions/dynamic_rendering/README.adoc

Yet another blog explaining Vulkan synchronization – Maister's Graphics Adventures

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值