Pixel 的生命周期

客户端请求一组命令作为未来取景帧的一部分呈现。单个风景优美的帧可以有多个客户端“演示”,其中每个“演示”代表一个 Flatland 实例对全局场景图的更新。 本文档介绍了 View 的内部架构,以说明请求如何变为像素。

下图显示了在客户端请求请求时,客户端会遵循的步骤。Flatland 是一种多线程系统,除了处理负责合成的中央渲染线程之外,Flatland 实例各自位于自己的线程上。

平面游戏中像素的生命周期

  1. 客户端会对 Flatland API 进行各种调用以修改其场景图、创建转换和矩形,以及添加图片。当客户端创建映像时,该映像会注册到 BufferCollectionImporter API 的多个实现,其中包括 Vulkan 和显示控制器实现。每个域都会创建一个由 sysmem 支持的域的内部表示(例如,适用于 Vulkan 的 Vulkan 映像),该域会由 sysmem 支持(稍后会变得非常重要,请参阅第 8 步)。准备就绪后,客户端就会调用 Present() 进行提交。

  2. FrameScheduler 决定何时应用 Present() 调用。它会使用自己的内部政策,尽早唤醒,以在下一个 vsync 之前呈现帧。

  3. 每个 Flatland 实例都与自己的 UberStruct 相关联,后者是特定 Flatland 实例本地的数据集合,代表该实例的最新状态提交记录。UberStruct 表示 Flatland 实例的本地状态的快照。因此,它仅包含数据,而不引用外部资源。调用 Present() 后,Flatland 实例的 UberStruct 会在此时更新。

  4. 接下来,UberStruct 数据需要由 UberStructSystem 进行编译。UberStructSystem 是所有父结构的中心管理器,也是将 Flatland 实例中的本地数据(超级结构体)聚合到整个场景图的快照以供呈现循环使用的系统。 更具体地说,UberStructSystem 会获取其获取栅栏已发出信号的所有 Uberstruct 的原子快照。其目的是让单独的工作器线程拥有每个 Flatland 实例,计算其本地线程中的本地数据(例如拓扑向量),然后将这些向量同时提交到 UberStructSystem

  5. 在此示例中,UberStructSystem 数据会被发送到 Engine,后者会将来自多个 Flatland 实例的数据展平为长长的一维数据数组,这些数据数组适合处理低级别图形和显示处理。引擎也是对矩形可渲染数据执行遮挡剔除的位置。

  6. 此时,呈现过程有两种可选方式。 Flatland 能够执行从直接显示到屏幕合成以及基于 Vulkan 的 GPU 合成。DisplayCompositor 负责管理这两种渲染路径,并选择用于特定帧的渲染数据集集。首选从直接显示到显示渲染路径,因为它允许将内容直接合成到设备硬件层,从而跳过成本高昂的渲染计算任务。不过,层数有限(具体取决于特定设备),并且关于设备应如何向这些层应用图片以及设备专用规则也有所不同。如果满足这些条件,我们将直接跳到第 7 步。否则,请转到第 8 步。

  7. 在直接合成到显示合成期间,DisplayCompositor 将获取 RectangleRenderable 数据并将每个矩形分解为要应用到的图层的 sourcedest 数据。Source 数据是指要合成的图片的纹素的剪裁尺寸。Dest 数据是指图片将在显示屏上占据的屏幕空间像素尺寸。我们还尝试直接在此处进行颜色转换。

  8. 如果无法直接合成到屏幕合成,我们将回退到 GPU 合成。渲染数据从 DisplayCompositor 发送到 VkRenderer。在执行上面列出的任何步骤之前,当客户端在其 Flatland 实例中将图像设置为内容时,这些图像会注册到 VkRenderer(第 1 步),从而基于这些图像创建 sysmem 支持的 Vulkan 纹理。完成此步骤后,Vulkan 纹理的创建工作就已经完成了。这意味着,在将渲染数据传递给 RectangleCompositor(下文中的第 9 步)之前,所有 VkRenderer::Render() 函数都需要创建新的 Escher 帧,通过转换其图像布局并计算适当的标准化 UV 坐标,准备要渲染的纹理,并设置 Vulkan 信号量以在信号完成时发出信号。

  9. 数据从 VkRenderer 向下传递到 RectangleCompositorRectangleCompositor 是一个通用的 2D Vulkan 合成器,它利用 Escher 将图像数据数组渲染到输出图像(帧缓冲区)。为了提高效率,不透明和透明的数据将分别处理。不透明数据会前后循环遍历,而透明数据会前后更新,在此过程中 Vulkan 命令缓冲区会更新,以及渲染所需的其他数据(例如推送常量)。

  10. 所有命令都已推送到 Vulkan 命令缓冲区后,我们深入 GPU 层,渲染数据则由我们的 Flatland 专用顶点和 Fragment 着色器进行处理。此外,如果尝试直接渲染到显示时,未成功应用颜色转换,此处也会调用 Flatland 颜色转换着色器,它会在主渲染通道后直接计算子校验和。

  11. 所有数据应用到屏幕控制器配置后,我们调用 ApplyConfig,用于提交更改。完成此操作后,所有渲染的数据都将显示在屏幕上。