《Vulkan Tutorial》 笔记 14:Render Passes
本部分结果可参考 14_Render_Passes
本章涉及到的关键对象和流程如下所示
在设置完 Fixed functions 后,在完成创建 Pipeline 时最后依赖的就是 Render Pass。开发者需要告诉 Vulkan 在渲染时需要使用的 Framebuffer Attachments,以及每个 Framebuffer 有多少个 Color / Depth Buffer,需要有多少次采样点(MSAA)等等信息,这些信息都会封装在 Render Pass
中。
为创建 Render Pass,在 GraphicsPipelineMgr
中增加函数 createRenderPass
和 destroyRenderPass
,在 HelloTriangleApplication
的 initVulkan
和 cleanup
中分别调用这两个函数:
1 |
|
#Attachment Description
在 createRenderPass
中首先需要创建 VkAttachmentDescription
对象,表示 Framebuffer 中的 Attachment。Framebuffer 中的 Attachment 可以是 Color Buffer / Depth Buffer / Stencil Buffer 等等。目前仅需创建一个 Color Attachment,用于输出到 Swap Chain:
1 | void GraphicsPipelineMgr::createRenderPass() |
- Color Attachment 的格式与创建的 SwapChain 中的 Image 格式相同
- 目前因为未开启 MSAA,因此
samples
的类型为VK_SAMPLE_COUNT_1_BIT
。 loadOp
设定在渲染前,该如何对待 Framebuffer 中已有的数据:VK_ATTACHMENT_LOAD_OP_CLEAR
:清空已有的数据VK_ATTACHMENT_LOAD_OP_DONT_CARE
:对如何处理已有数据的行为是未定义的,因为并不关心这些数据VK_ATTACHMENT_LOAD_OP_LOAD
:保留并加载已有的数据(如需要保留上一次渲染结果时使用)
storeOp
设定渲染后,该如何对待渲染的结果数据,可能的选项为:VK_ATTACHMENT_STORE_OP_STORE
:渲染的结果数据会存储在内存中,并在后续读取VK_ATTACHMENT_STORE_OP_DONT_CARE
:对如何处理渲染结果数据的行为是未定义的
- 因为
loadOp
及storeOp
只设定 Color 和 Depth 的数据,因此还需要stencilLoadOp
和stencilStoreOp
设定 Stencil 数据。 initialLayout
和finalLayout
用于设定 Image 的 Layout- Vulkan 中都通过
VkImage
表示 Textures 和 Framebuffers,可以根据使用 VkImage 的目的来修改内存中像素的 Layout,比较常用的可选参数为:VK_IMAGE_LAYOUT_UNDEFINED
:Image 的初始内容不重要,可能会被丢弃VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
:Image 会用于 Color AttachmentVK_IMAGE_LAYOUT_PRESENT_SRC_KHR
:Image 会用于作为 Swap Chain 的 Presentation SourceVK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
:Image 会作为内存拷贝的目的地
initialLayout
表示渲染前 Image 的 Layout,因为这里将loadOp
设定为VK_ATTACHMENT_LOAD_OP_CLEAR
,即每次渲染前都会清空 Image 数据,所以这里并不关心 Layout,设定为VK_IMAGE_LAYOUT_UNDEFINED
finalLayout
表示渲染后 Image 的 Layout,这里因为最终图像用于 Swap Chain 的 Present,所以选为VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
。
- Vulkan 中都通过
关于 Layout 的配置项,会在后续的 Texture 章节中进一步介绍。
#Subpasses and attachment references
一个 RenderPass 可以包含多个 Subpasses,Subpass 是一系列依赖于之前 pass 执行后 Framebuffer 内容的渲染操作。如有一系列的后处理,每一个后处理都依赖于前一个处理的结果。
当把一系列的 Subpasses 封装在一个 Renderpass 中后,Vulkan 可以重新排列这些 Subpasses 或节省带宽以获得最好的性能。
对于每一个 Subpass,它都可以引用一个或多个 Attachment。通过结构体 VkAttachmentReference
表示 Attachment Reference,如下:
1 | void GraphicsPipelineMgr::createRenderPass() |
其中:
attachment
表示定义的一系列 Attachments 中需要引用的 Attachment 的 Index 值,因为之前只定义了一个VkAttachmentDescription
,因此这里引用第一个,设为 0。layout
设定 Attachment 在被 Subpass 使用时希望的 Layout。Vulkan 会在 Subpass 启动时自动的将 Attachment 转换到设定的 Layout。这里希望在 Subpass
运行时将 Attachment 作为 Color Buffer,因此设定为VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
。
创建完 Attachment Reference 后,即可创建 Subpass:
1 | void GraphicsPipelineMgr::createRenderPass() |
其中:
pipelineBindPoint
表示 Subpass 在管线中的绑定点,这里是用于渲染的,所以作为 GRAPHICS,在 Vulkan 的规划中还会支持 Compute Subpass。pColorAttachments
表示 Subpass 引用的 Color Attachment,除了 Color Attachment,还可以依赖:pInputAttachments
:从 Shader 中读取的 AttachmentpResolveAttachments
:用于 MSAA 的 Color AttachmentpDepthStencilAttachment
:表示 Depth 和 Stencil 的 AttachmentpPreserveAttachments
:这些 attachment 在本 subpass 不被访问,但其内容需要在后续 subpass 保持不变
#Render Pass
最后装填结构体 VkRenderPassCreateInfo
创建 RenderPass:
1 | void GraphicsPipelineMgr::createRenderPass() |
destroyRenderPass
函数中即调用 vkDestroyRenderPass
销毁 Render Pass。
1 | void GraphicsPipelineMgr::destroyRenderPass() |