| RFC-0161:Scenic 分配器 API | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 用于 API 校准的 Scenic 分配器的旧版 API 设计文档。 |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2021-03-19 |
| 审核日期(年-月-日) | 2021-04-05 |
之前的 API 设计文档
此 RFC 之前以 API 设计文档的形式提交,后来在 API 设计文档模板被弃用后转换为 RFC。
摘要
本文档提出了一项计划,旨在将 Scenic 的图片资源分配提取到单独的协议中。
目标和使用场景
分配器 API 旨在改进现有的图片分配流程,并使其与即将到来的变更兼容。
将分配的 BufferCollection 资源的范围从 Scenic::Session 扩展到 Scenic::Session。一个 BufferCollection 可用于在多个 Scenic::Session 和即将推出的 2D API Flatland 的会话中创建 Image 资源。
将缓冲区分配与 Scenic::Session 分开,可明确协议的用途。 分配器仅处理缓冲区分配,而 Scenic::Sessions 用于呈现和绘制。
我们的 3D API 以及即将推出的 2D API 都可以使用分配器。这样,您就可以使用更复杂的图形。
借助此 API,更复杂的用户可以在其独立的 Scenic::Session 之间共享图片资源。目前无法实现,因此经常需要重新分配。
设计
我们的建议主要是将缓冲区注册和注销功能从 Scenic::Session 移至新协议。请参阅下文了解建议的协议。
library fuchsia.ui.composition;
/// A typed wrapper for an eventpair, representing the registry endpoint of a buffer collection.
resource struct BufferCollectionExportToken {
zx.handle:EVENTPAIR value;
};
/// A typed wrapper for an eventpair, representing the Image import endpoint of a buffer
/// collection.
resource struct BufferCollectionImportToken {
zx.handle:EVENTPAIR value;
};
protocol Allocator {
/// A BufferCollection is a set of VMOs created by Sysmem and shared by a number of
/// participants, one of which is the Flatland Renderer. Some content, such as Images, use a
/// BufferCollection as their backing memory.
///
/// Clients can send `export_token` to register buffer collections with Allocator to be used
/// later in [`fuchsia.ui.composition/Flatland`] instances or other Scenic APIs. For
/// example, by passing a [`BufferCollectionImportToken`] containing the matching peer of
/// [`BufferCollectionExportToken`], they can create image resources via
/// [`fuchsia.ui.composition/Flatland.CreateImage`]. Clients should wait for the response
/// before using `import_token`.
///
/// Flatland participates in the allocation of buffers by setting constraints on the
/// BufferCollection referenced by `buffer_collection_token`. It will not block on buffers
/// being allocated until the client creates content using the BufferCollection.
///
/// The buffer collection registered with `export_token` is available and kept alive as long
/// as the client holds a valid [`BufferCollectionImportToken`]. They will be garbage collected
/// when all [`BufferCollectionImportToken`]s are closed and all the associated Image resources
/// are released.
RegisterBufferCollection(BufferCollectionExportToken export_token,
fuchsia.sysmem.BufferCollectionToken buffer_collection_token)
-> () error RegisterBufferCollectionError;
};
图 1 - 映像创建流程
请注意,不再需要取消注册缓冲区。这可以通过在客户端上舍弃所有 BufferCollectionImportToken 实例来隐式完成。考虑到许多客户端在意外关机时无法正常执行取消注册流程,此方法可以更好地防范内存泄漏。
现有的缓冲区注册功能要求客户端定义一个唯一 ID 来引用 BufferCollection。此参数已替换为 EVENTPAIR,客户端可以根据需要轻松复制任意次数以供参考。请参阅下面的现有流程。
protocol Session {
RegisterBufferCollection(uint32 buffer_id, fuchsia.sysmem.BufferCollectionToken token);
DeregisterBufferCollection(uint32 buffer_id);
};
我们一直在努力实现建议的设计,并且已经完成了必要的重构。 如需了解实际更改,请参阅 fxr/498558 和 fxr/499479。
易用性
分配器 API 提供了一种不同的方式来实现现有功能,从客户端的角度来看,这种方式更简单。
- 客户端创建 EVENTPAIR,而不是确定唯一 ID。
- 客户端可以舍弃事件对的另一端,而不是使用相同的唯一 ID 显式调用 DeregisterBufferCollection。
- 客户端可以复制并使用多个 Scenic::Session 中的事件对的另一端来创建图片资源。
如需查看 Scenic::Session 的使用模式示例,请参阅下文。
fuchsia::ui::composition::AllocatorPtr scenic_allocator;
fuchsia::sysmem::BufferCollectionTokenSyncPtr token;
auto ref_pair = allocation::BufferCollectionImportExportTokens::New();
scenic::SessionPtr session;
scenic_allocator->RegisterBufferCollection(std::move(ref_pair.export_token), std::move(token),
[&]() {
session->Enqueue(scenic::NewCreateImage3Cmd(
image_id, width, height,
std::move(ref_pair.import_token), vmo_index));
});
测试
我们计划围绕我们的 API 添加广泛的单元测试。需要将分配器与 Scenic::Session 协同使用的集成测试可以通过转换我们的树内像素测试来完成。
性能考虑因素
分配器 API 不会添加任何额外的 API 调用。这样可以避免客户端执行 DeregisterBufferCollection 调用。
安全注意事项
分配器 API 依赖于 EVENTPAIR 功能来解决安全问题。EVENTPAIR 的唯一性以及在创建时与其他端点的紧密联系可确保恶意客户端无法劫持和访问底层缓冲区。如果他们以某种方式获取了 EVENTPAIR,则只能展示此图片,而无法修改或读取它。
缺点和替代方案
分配器 API 提案有两项主要改进,这两项改进都可以通过现有协议和流程来替代。
- 我们可以继续使用唯一 ID 来引用缓冲区集合,而不是事件对。我们可以预期客户端会选择唯一的集合标识符,也可以通过注册调用返回唯一的集合标识符。
- 选择唯一标识符需要同步,包括客户端查找可用的标识符,以及等待分配器的确认才能使用该标识符。
- 恶意客户端可能会轻易劫持唯一标识符。
- 我们需要显式调用 DeregisterBufferCollection()。
- 我们可以将分配器保留在 Scenic::Session 和 Flatland 实例中,而不是公开新协议。
- 使用多个会话的复杂客户仍会受到限制,无法使用注册会话以外的缓冲区集合。