Scenic是将来自多个进程的图形对象组合成共享场景图的Garnet服务。这些对象在统一的光照环境下渲染(到显示器或其他渲染目标上)。这意味着即使原始进程彼此相互不了解,对象也可以投射阴影或将光反射到彼此之上。
Scenic的职责包括:
- 合成:Scenic提供保留模式的3D场景图,其中包含由客户独立生成和链接而成的内容。合成使得无缝混合多个单独实现的UI组件的图形内容变得可能。
- 动画:在渲染每个帧之前,Scenic会重计算模型中的任何时变表达式,从而实现无需客户端的进一步干预即可启用模型属性的动画。将动画卸载到Scenic可确保平稳无抖动的转换。
- 渲染:Scenic使用Escher渲染其场景图。Escher是一个基于Vulkan的渲染库,它将逼真的光照和阴影应用到整个场景中。
- 调度:Scenic调度场景的更新和动画,以预测和匹配渲染目标的演示延迟和刷新间隔。
- 诊断:Scenic提供诊断界面,以帮助开发人员调试模型和衡量性能。
名为SceneManager
的FIDL接口是Scenic的前端,接口中的每个实例均代表一个Scenic实例(我们计划尽快将接口重命名为Scenic
)。每个Scenic实例都是一个独立的渲染上下文,具有自己的内容、渲染目标和调度循环。并提供以下操作:
- 创建客户端的
Session
,用于将图形内容发布该实例。 - 创建渲染目标以指定实例被渲染后输出的位置,例如显示器或图像(如屏幕截图)。
- 将场景绑定到渲染目标上。
- 获得另一个绑定到同一个Scenic实例上的Zircon通道(复制)。
单个Scenic实例可以在同一个调度循环中更新,动画和渲染多个Scene
(图形对象树)到多个串联而成目标上。这意味着Scenic实例的时序模型是一致的:其所有相关内容属于同一个调度域内,并可以无缝进行混合。
相反地,独立的Scenic实例不能共享内容,因此它们之间是不一致的。创建单独的Scenic实例对于渲染具有相当不同调度要求的或需单独运行测试的目标非常有用。
当Scenic实例被销毁时,其所有会话都将无法运行,同时渲染也将停止。
View
通常不直接处理Scenic实例。相反,他们从视图管理器处获得Scenic的Session
实例。
Session
的FIDL接口是Scenic客户端使用的主要API,以Resource
的形式提供图形内容。每个会话都有自己的资源表,并且无法直接与属于其他会话的资源进行交互。
每个会话提供如下的操作:
- 提交添加、删除或修改资源的操作。
- 提交一系列以原子方式呈现的操作。
- 等待和发送栅栏信号singal。
- 调度后续帧的更新。
- 与其他会话(通过协商)形成链接。
会话被销毁时,其所有资源都将被释放,并且所有链接都无法运行。
View
通常从视图管理器处接收单独的会话。
Resource
表示场景中的元素,例如属于特定Session
的节点、形状、材质和动画等。
位于//garnet/public/fidl/fuchsia.ui.gfx/resources.fidl
的API描述了Scenic的资源列表。
Scenic的客户端通过排队和提交操作来生成要呈现的图形内容,以添加、删除或修改其会话中的资源。
每个资源在其会话中由本地唯一ID标识,该ID由会话所有者(通过任意方式)分配。会话不能直接引用属于其他会话的资源(即使它知道这些资源的ID)。因此会话之间的内容嵌入是通过使用Link
对象作为中介来执行的。
为了添加资源,需要执行以下步骤:
- 将操作排队以添加所需类型的资源,并在会话中为其分配唯一本地ID。
- 将一个或多个操作排入队列,在指定其ID的条件下设置该资源的属性。
某些更复杂的资源可能会在其自定义中引用其他资源的ID。例如,Node
引用它的Shape
,因此必须在Node
之前添加Shape
,以便Node
可以将它作为其定义的一部分引用。
要修改资源,请将一个或多个操作排入队列,以便以添加资源时使用的相同方式设置所需的属性。
为了删除资源,需要将操作排入队列。删除资源会导致其ID重新变成重用状态。但是,会话维护了每个内部引用资源的引用计数,底层存储在所有剩余资源的引用被清除和直到下一帧不需要依赖这些资源之前将不会被释放(并且不能被重用)。这对于Memory
资源尤为重要,请另参见栅栏。
添加、修改和删除过程可以无限次地重复,以递增地更新会话内的资源。
Node
资源表示可以组装成名为节点树(node tree
),并用于渲染的层次结构的图形对象。
TODO:更详细地讨论这个问题,尤其是分层建模概念,例如每个节点的转换、分组、添加和删除子节点等。
Scene
资源将节点树(node tree
)与渲染它所需的场景范围参数组合在一起。一个Scenic实例可能包含多个场景,但每个场景必须有自己独立的节点树。
场景资源具有以下属性:
- 场景的根node节点。
- 场景的全局参数,例如其照明模型。
为了对一个场景进行渲染,必须有Camera
对象指向它。
合成器是两种形式的资源:DisplayCompositor
和ImagePipeCompositor
。它们的工作是将LayerStack
的内容绘制到渲染目标中。对于DisplayCompositor
而言,目标显示器可能有多个硬件覆盖:在这种情况下,合成器可以选择将这些中的每一个与单独的层相关联,而不是将这些层平展为单个图像。
LayerStack
资源由Layers
的有序列表组成。每一层都可以包含一个Image
(可能由矩阵变换而成),或者一个指向要渲染Scene
的Camera
资源(如上所述)。
添加相应的章节以讨论所有其他类型的资源,包括形状、材料、链接、内存、图像、缓冲区、动画、变量和渲染器等。
TODO:讨论帧调度,演示时间戳等。
TODO:讨论同步。
讨论如何上手使用Scenic,运行示例和推荐的实现策略等。