RFC-0162:Flatland API

RFC-0162:Flatland API
状态已接受
领域
  • 图形
说明

描述 Flatland,它是 Fuchsia 的 2D 合成 API。

Gerrit 更改
作者
审核人
提交日期(年-月-日)2021-05-24
审核日期(年-月-日)2021-05-30

旧 API 设计文档

此 RFC 之前作为 API 设计文档提交,并在 API 设计文档模板被废弃后转换为 RFC。

摘要

本文档提出了一个适用于 Fuchsia 图形客户端的 2D API。Flatland 为客户端提供类似于显示控制器的功能,其中的资源是在 2D 世界中定义的。

目标和应用场景

景观目前在 fuchsia.ui.gfx 命名空间(“gfx API”)下通过 3D API 为图形客户端提供 3D API。此 3D API 可为客户端提供类似于视频游戏引擎或其他 3D 图形程序的场景模型。绘制顺序由 Z 深度处理,不透明度通过基于深度的 alpha 混合处理。遗憾的是,无论是从产品和性能的角度来看,gfx API 都不再适合在景观平台上满足的需求。群组不透明度等功能是不可能的,因为如何处理一组半透明内容的阴影尚不明确。

从产品的角度来看,我们当前的客户都是 2D 产品。没有深度和绘制顺序的概念。只是按照提交不同批次的绘制几何图形的顺序。由于没有深度,透明度效果也取决于绘制顺序。“2D”客户端(通过 Flutter、Chromium 和会话框架)必须执行额外的工作,才能解决 Views 的 3D 场景表示与用户体验的 2D 表示不一致的问题。

从性能角度来看,新型视频显示控制器 (VDC) 硬件提供加速功能(例如多个显示平面和硬件叠加层),Sce 将来希望利用这些功能来降低功耗和 GPU 使用量。但是,硬件以严格 2D 模式运行,并且只理解可按 X/Y 定位的矩形层。Views 的当前 3D API 允许并鼓励客户提交不符合此范式的内容,并阻碍优化尝试。

通过公开真正的 2D API,我们打算让 2D 客户端变得更精彩:

  • 2D API 更符合 2D 客户的期望。
  • 尽可能将工作委托给 VDC,以减少 GPU 用量。
  • 更轻巧的景观,仅针对 2D 矩形图层进行了优化。

设计

我们的建议是从头开始编写一个 2D 协议,不要重复使用 fuchsia.ui.gfx 的某些部分。

提议的 2D API 的当前状态位于在此审核过程中提交的 fuchsia.ui.scenic.internal.flatland 库中。请查看并留下评论。

以下是围绕 Flatland API 所做的一些总体决策的说明:

  • Flatland 严格遵循并提供类似于 fuchsia.hardware.display/Controller 中定义的屏幕控制器 API 的功能。
    • 性能最佳的场景是景观中的 Flatland 实现将其资源传递到显示屏而不进行合成。因此,显示屏控制器 API 存在以相同方式定义的通用资源。即,用作围栏(在可以安全访问资源时发出信号)的 zx.handle:EVENT 通过这些协议进行传输,并具有相同的含义和用途。
  • Flatland 旨在为客户端提供确定性的 CPU 费用。有一个按时限预定的渲染线程。每个 Flatland 会话均在各自的调度程序上运行,这些调度程序在当前配置中位于各自的线程上。
    • 可能有多个 Flatland 会话,其中每个会话都是一个与 Flatland 通信的通道,以便在显示屏上渲染到一个矩形层。这些会话可能不会相互影响彼此的演示或性能流程。
  • 图片分配是通过在 fuchsia.ui.composition/Allocator 下定义的景观分配器协议强制完成的。
    • 所有映像使用都是零复制,因为客户端和景观使用 Sysmem 进行分配之前就分配和格式达成一致。
    • 分配器允许在多个 Flatland 会话中使用图片。
  • Flatland 不提供命令联合模式。Present() 调用是用于处理已加入队列的命令的标记,这些命令是单独的方法。
    • Flatland 严格限制客户端可以调用 Present() 的次数。这将通过响应 OnPresentProcessed() 进行传达。该限制可用作限制机制。
    • Flatland 可能会在 OnPresentProcessed() 回调中返回 Error,以通知客户端存在非法操作。随后,Flatland 通道将关闭。
  • Flatland 希望客户端定义并跟踪唯一资源标识符。类型安全由围绕这些标识符定义的结构体强制执行,例如 TransformId 和 ContentId。
  • Flatland 使用挂起获取 (Hhanging-get) 将链接结构或属性更改告知客户端。这些模块通过单独的协议发出。

未知

在某些领域,平面设计可能会进行改进,以更好地满足客户的需求。

  • 客户端可能会希望合成器处理某些显示硬件未处理的 2D 效果,例如模糊处理。这些操作的费用更高。我们计划通过分离这两种操作类别来明确这一区别。Flatland 的当前状态仅支持可由屏幕处理的操作。
  • 演示和反馈流程会根据客户的反馈不断完善。在定义当前的 Flatland 流之前,我们对 gfx API 的呈现流程进行了三次迭代。因此,PresentArgs 被定义为一个表,可以为未来的更改提供一定的灵活性。
    • 我们在设计和演示反馈中重点关注低延迟客户端和高吞吐量客户端。OnPresentProcessed() 会在适合开始下一帧工作时通知客户端。OnFramePresented() 会告知高级客户端有关呈现的帧何时到达屏幕的时间。

易用性

请查看 flatland_unittest 树内测试,找到大量使用 Flatland API 的示例。

下图说明了链接多个 Flatland 会话的连通图的工作原理。这是一个更复杂但常见的用例。

图 1 - Flatland 此图显示了 Flatland API 之间的关联。

测试

Flatland 目前定义为内部 API,测试由树内单元测试提供。由于除了测试之外,没有其他运行 Flatland 代码的方法,因此我们使用自动化测试广泛涵盖每个代码。我们计划保持此测试的覆盖范围和质量。

我们计划最终将每个图形示例转换为 Flatland。我们并不需要严格生活在 3D 环境中的任何客户端。我们目前正在致力于让 Flatland Presenter 成为添加和迁移树内集成测试的基础 (https://fxbug.dev/42156206)。这有助于我们为将来的一些关键外部客户端(例如 Flutter 和 Chromium)迁移做好准备。

Flatland 旨在允许运行业务逻辑,而无需依赖于硬件功能(例如 Vulkan 和显示屏)。Vulkan 可被 null 渲染程序实现交换,该实现会跳过合成。显示屏可以更换现有的模拟显示屏实现。

其他 Flatland API 集成测试将在兼容性测试套件下提供。

性能注意事项

Flatland 旨在允许许多客户端同时运行,而不会影响彼此的工作。

  • 每种方法是单向 FIDL 方法,表示客户端要渲染到显示屏的矩形部分的命令。Present() 会发出信号,表明来自客户端的命令序列已结束,并表明协作平台开始处理下一次显示屏更新。
  • 大多数客户端在主动更新其内容时,会在每次 vsync 至少执行一次调用。对于 60 fps 的显示场景,该值约为 16 毫秒。在每个 vsync 间隔中:
    • 客户端可以进行 N 次调用来修改场景图,随后进行一次 Present() 调用。
    • Flatland 发出 OnPresentProcessed() 以告知客户端相应操作已加入队列,且客户端应开始生成下一帧。目前,我们的客户不知道何时开始工作,并依靠硬编码偏移来避免重叠,而 OnPresentProcessed() 可以解决此问题。此反馈还会为客户端提供有关未来理想的 Present() 调用的提示,并告知他们 Present() 的允许情况。
    • 客户端可能会忽略 OnPresentProcessed() 中给出的时间和提示,并根据其内部时钟继续呈现。这种做法仍然有效,但无法保证可以避免资源争用。
    • Flatland 会发出 OnFramePresented() 以告知客户端相应内容实际上已显示在屏幕上。此反馈对于高级客户端的同步(例如音频/视频)是必需的。
  • Flatland 通过明确定义 num_presents_returned 来阻止恶意客户端将过多的 Present() 调用加入队列。客户端调用 Present() 的次数不得超过 OnPresentProcessed() 允许的次数。每个客户端在开始时都包含一个当前限额。
  • 请注意,Flatland 使用自己的调度程序运行每个频道连接。这些反馈机制是异步的。

安全注意事项

Flatland 用户彼此隔离。唯一资源标识符仅在其渠道的范围内定义。它们只能定位由其父级 Flatland 会话定义的屏幕部分。

每种错误情况都会导致 Flatland 通道关闭。在这些错误状态下,不清楚应在界面上绘制什么内容,因此我们看不到任何允许客户端继续演示的时间点。

隐私注意事项

Flatland 不会公开任何设备标识符或隐私敏感信息。客户端不会直接与硬件交互。

Flatland 允许客户端通过 SetDebugName() 设置可识别的调试字符串。在输出有关错误的详细系统日志时,此字符串用作前缀,以帮助客户端区分错误。客户端可以完全控制在此处设置的内容,如果未设置,则系统日志中没有前缀。

缺点和替代方案

我们从 fuchsia.ui.gfx 下的现有 3D API 中了解到,我们做出决定 Flatland 的 2D API 的依据。在制定设计决策时,我们考虑了所有用户反馈、错误和经验教训。

  • 我们可以选择在现有 3D API 下演变 2D API。不过,存在一些根本区别,可能会使客户端和实现变得不必要的复杂。
  • Flatland 可以使用命令联合模式,就像 fuchsia.ui.gfx 一样。目前,每个 Flatland 命令都作为 FIDL 方法进行映射。做出此决定是因为使用 3D API 中的现有命令模式观察到的负面结果。我们不得不向客户提供和维护不同语言的封装容器。不过,将每条评论作为一种方法进行映射会带来一些负面影响。这种设计可防止批量处理消息,直到支持单次写入多条消息为止。但是,我们预计客户端不会经常操控场景图,也不会考虑到这代价高昂。

后续工作

我们计划从以下方面着手改进 Flatland API:

  • 每个 Flatland 实例都有一个与之关联的 ViewRef,以及用于获取您和您的子项的 ViewRef 的方法。请参阅 https://fxbug.dev/42159888
  • “工厂函数”,用于将输入协议绑定到特定的 Flatland 实例,从而将其范围限制为实例的视图子树。请参阅 https://fxbug.dev/42159922
  • 大小和指标以单向流动的方式从父帧流向子对象,但父帧(和中介服务器)不知道这些大小和指标是哪个帧生效的,除了第一帧之外。这会产生连带影响:用户会看到有缺陷的帧,而其他 API 会受到客户端逻辑延迟的影响。请参阅 https://fxbug.dev/42156345
  • 我们考虑在多个实例之间同步 Present(),但该问题尚未得到解决。请参阅 https://fxbug.dev/42159935
  • Flatland 将位于 fuchsia.ui.composition 命名空间及其依赖项下。fuchsia.scenic.allocation 和 fuchsia.scenic.scheduling 也移到了其下。请参阅 https://fxbug.dev/42158797