17Vulkan——缓冲区资源和RenderPass

1.缓冲区资源

  缓冲区资源以线性方式表示连续的数据阵列。 缓冲区资源通常用来存储属性数据信息,如顶点座标,纹理座标,关联颜色等。 Vulkan 中的缓冲区资源由 VkBuffer 对象表示,与视图形式(图像视图,VkImageView)表示的图像资源(VkImage)不同,缓冲区资源可以直接用作顶点数据的源,或者可以通过着色器利用描述符进行访问。 需要把它们显式转换为缓冲区视图(VkBufferView)以允许着色器以格式化的格式使用缓冲区数据的内容。

使用 Vulkan API 创建缓冲区资源(VkBuffer)的步骤说明

  1. 创建缓冲区对象:使用 vkCreateBuffer()API 创建缓冲区对象(VkBuffer)。 此 API 会用到 VkCreateBufferInfo 结构对象,该对象指定了用于创建缓冲区对象的一些重要缓冲区元数据。 缓冲对象的 VkCreateBufferInfo 包含必要的内存信息,例如格式,用法,大小,创建标志等。 这个信息用于从设备分配物理内存。 您可以认为在此初始阶段的缓冲区对象没有后端的内存支持,即没有分配实际的物理存储。 创建缓冲区对象并不意味着物理分配在幕后自动完成;必须手动完成,这会在下一步中介绍。
  2. Allocating buffer memory 分配缓冲内存
  • 获取内存需求:使用 vkGetBufferMemoryRequirements()API 收集所需的内存信息。 在缓冲区资源的分配过程中,此信息有助于分配所需的适当大小的内存。 这个 API 使用到了第一步中创建的 VkBuffer。
  • 确定内存类型:与图像资源类似,从可用的内存类型中获取合适的内存类型,并选择与用户所需属性匹配的内存类型。
  • 分配设备内存:使用 vkAllocateMemory()API 分配设备内存(VkDeviceMemory)。
  • 暂存:分配物理内存后,需要使用 vkMapMemory()将其映射到本地主机,以便将几何图形的数据从主机内存上载到物理设备内存。 一旦数据被复制到物理设备内存中,就需要使用 vkUnmapMemory()来取消映射。
  • 绑定分配的内存:使用 vkBindBufferMemory()API 将设备内存(VkDeviceMemory)绑定到缓冲区对象(VkBuffer)。

下图总结了完整的缓冲区资源创建的工作流程:

2RenderPasss渲染通道

  在Vulkan中,绘制命令会被组织成Render Pass,可以说是一组SubPass的集合,每个子通道描述的是如何使用color attachments 等图像资源,RenderPass管理子通道之间的依赖关系和绘制顺序:

渲染通道告诉我们关于渲染时要使用的帧缓冲附件和子通道的信息 渲染通道主要由两种类型的组件组成:附件和子通道。

附件 Attachments

附件是指渲染命令时使用的表面区域(例如颜色,深度 / 模板或用来执行解析操作的解析附件)。 这里描述了五种类型的附件:

  • 颜色附件:Color attachment,颜色附件表示在其上绘制渲染图元的、用来绘图的目标图像。
  • 深度附件:Depth attachment,深度附件存储深度信息并将其用于深度 / 模板测试操作。
  • 解析附件:Resolve attachment, 解析附件自动从多采样附件一直向下采样到子通道末尾相应的单采样附件。 解析附件对应于多重采样的颜色附件,并且表现得好像子通道末尾有一个 vkCmdResolveImage,从彩色附件到相应的解析附件。 一个例外是驱动程序可能会做得更好,例如同时对一个贴片 tiler 执行溢出 spill 和解析 resolve 操作。
  • 输入附件:Input attachment,这个附件由着色器共享的附件列表组成。 输入附件类似于受限纹理,其中着色器可以执行的唯一操作是纹素的提取(texture(tex,uv)) - 即从纹素读取(对应于当前正被着色的像素)。 明显的例子是一触式后(期)处理过滤器(无模糊等),经典的延迟渲染器的光照阶段就是从 G 缓冲区中读取等。
  • 保留附件:Preserve attachment,在整个过程中,在给定的子通道中,保留附件内的内容保持不变。 保留附件根本不在其他 API 中表达。 他们表示要求保留一些附件的内容(因为它将在以后使用),但不应该被当前的子通道所触及。 这在桌面 GPU 上根本没有意义,其中渲染目标写入操作会直接进入内存。 然而,对于平铺器 tiler 来说,这就显得非常有趣:在子通道期间,片上内存的附件部分可以被重新使用以代替某些其他附件,而不必将其内容泄漏回内存。

子通道 Subpasses

在渲染通道中,子通道读取和写入相关的附件。 Render Pass 执行中的当前子通道会受渲染命令的影响:

  • 一个子通道可以读取先前被写入的附件(它必须保存)并写入当前与其关联的附件。
  • 写入颜色和深度 / 模板缓冲区也是与 Render Pass 实例关联的子通道附件的一部分。
  • 为了允许后续通道使用子通道附件,应用程序有责任确保信息保持有效状态,直到信息不被使用为止。
  • 在整个子通道的生命周期中,还有保留附件来保存附件中的内容。 子通道不能影响这些附件,因为它们是读 / 写保护的。 换句话说,它们在子通道生命周期中不能被读 / 写。
  • 子通道描述符由 VkSubpassDescription 定义。 它描述了子通道中涉及的附件数量。

  • 子通道可以引用各种附件,如输入,解析,颜色,深度 / 模板以及保留附件。 这是使用一个称为 VkSubpassDescription 的特殊控制结构来描述的

 4.实现渲染通道 Render Pass

Render Pass 实例是在创建命令缓冲区的准备阶段实现的。 对于每个交换链图像,都会创建一个相应的命令缓冲区对象。 这意味着,对于 n 个交换链图像,我们需要创建 n 个命令缓冲区对象。

  1. 创建的颜色图像和深度图像需要在附件中指定。 为这两个图像类型创建大小等于 2 的 VkAttachmentDescription 类型的数组。 此结构中指定的信息将决定在渲染通道 Render Pass 的开始和结束时如何处理图像。 其中包含图像格式,样本数量,加载和存储操作等。
  2. 对于这两个附件,将 loadOp 成员设置为 VK_ATTACHMENT_LOAD_OP_CLEAR。 这个设置的意思是在每个 Render Pass 实例开始时清除缓冲区。 对于颜色附件,将 storeOp 成员设置为 VK_ATTACHMENT_STORE_OP_STORE,指示渲染的输出保存在以后用于显示它的缓冲区中。
  3. 接下来,对于这两个附件,在 Render Pass 中指定绑定点。 这可以让渲染通道知道在哪里寻找一个特定的附件。 绑定点在 VkAttachmentReference 的帮助下定义;该控制结构摄入的另一条信息就是用于图像布局转换的图像布局信息。 分别为颜色和深度缓冲区使用 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL 和 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL 指定图像布局。 该布局通知底层引擎将图像存储在最佳内存中以提供最佳性能。
  4. 使用 VkSubpassDescription 在子通道中指定所有附件。 在这里,指定了颜色,深度,解析以及保存附件。 最后,所有附件和子通道特定的信息都在 VkRenderPassCreateInfo 中汇聚并传递给 vkCreateRenderPass()API 以创建 Render Pass 对象:
  5. 在销毁阶段,使用 vkDestroyRenderPass()API 销毁 Render Pass 对象

3.使用 Render Pass 以及创建 framebuffer

一旦创建 Render Pass,它就被用来创建帧缓冲区 framebuffer。 理想情况下,对于每个交换链彩色图像,我们需要一个与其相关的帧缓冲区。 例如,如果我们有一个双缓冲区交换链图像,那么我们需要两个帧缓冲区:一个用于前端缓冲区图像,另一个用于后端缓冲区图像。

实现帧缓冲区 framebuffer

FrameBuffer是一系列Image对象的集合,它是所有绘制操作的最终目标。

Swap Chains从窗口系统申请来的Image对象跟FrameBuffer绑定以后,绘制操作才能绘制到这些Image上面。

如果把绘制流程比作绘画:

Swap Chains从窗口系统申请来的Image是用来作画的纸张;

FrameBuffer就是一个可以夹住多张纸的画板;

Renderpasses则表示每张纸要画什么,他们之间的绘制顺序是什么样子的,绘制时是不是要参考前一张的绘制内容。

当绘制完成后,我们就可以把Image传给平台的窗口系统进行显示了。

 

帧缓冲区的实现很简单;按着如下步骤操作即可:

  1. 在 VulkanRenderer 类中创建以下函数和变量。 cmdFrameBuffer 声明负责创建帧缓冲区(frameBuffer)的命令缓冲区
  2. 初始化期间,使用 createFrameBuffer()函数创建帧缓冲区:
  3. 对于每个交换链彩色图像,创建其相应的帧缓冲区。 这是通过使用 vkCreateFrameBuffer()API 完成的。 此 API 使用 VkFrameBufferCreateInfo,我们在其中指定深度和彩色图像视图作为附件。 此外,在此结构中还传递了创建的 Render Pass 对象以及 framebuffer 的尺寸:
  4. 在应用程序的销毁阶段,使用 vkDestroyFrameBuffer()API 销毁所有的帧缓冲区:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章