RFC-0161:Sluk 分配器 API

RFC-0161:Scenic Allocator API
状态已接受
区域
  • 图形
说明

用于 API 校准的 Scenic 分配器的旧版 API 设计文档。

Gerrit 更改
作者
审核人
提交日期(年-月-日)2021-03-19
审核日期(年-月-日)2021-04-05

旧版 API 设计文档

此 RFC 之前是作为 API 设计文档提交的,后来在弃用 API 设计文档模板后,转换为 RFC。

摘要

本文档提出了一项提案,旨在将 Scenic 的图片资源分配提取到单独的协议中。

目标和用例

Allocator API 旨在改进现有的图片分配流程,使其与即将发生的更改兼容。

  • 扩大了 Scenic::Session 中分配的 BufferCollection 资源的范围。一个 BufferCollection 可用于在多个 Scenic::Session 中创建 Image 资源,以及我们即将推出的 2D API Flatland 的会话。

  • 将缓冲区分配与 Scenic::Session 分离可使协议的用途更加清晰。 分配器仅处理缓冲区分配,而 Scenic::Session 用于呈现和绘制。

  • 我们的 3D API 和即将推出的 2D API 都可以使用分配器。这样,您就可以使用更复杂的图形。

使用此 API,更复杂的用户可以在其独立的 Scenic::Session 之间共享 Image 资源。目前无法做到这一点,通常会强制重新分配。

设计

我们的建议主要是将缓冲区注册和取消注册功能从 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 - 图片制作流程 此图展示了客户端、分配器和呈现 API 之间的关系。

请注意,不再需要取消注册缓冲区。您可以通过在客户端上丢弃所有 BufferCollectionImportToken 实例来隐式执行此操作。考虑到许多客户端在意外关闭时执行取消注册流程时会遇到问题,因此这可以更好地防范内存泄漏。

现有的缓冲区注册功能要求客户端定义一个用于引用 BufferCollection 的唯一 ID。此参数已替换为 EVENTPAIR,客户端可以根据需要轻松复制该参数任意多次。请参阅下方现有流程。

protocol Session {
    RegisterBufferCollection(uint32 buffer_id, fuchsia.sysmem.BufferCollectionToken token);

    DeregisterBufferCollection(uint32 buffer_id);
};

我们一直在努力实现建议的设计,并且已完成必要的重构。如需了解实际更改,请参阅 fxr/498558 和 fxr/499479。

易用性

Allocator API 提供了一种实现现有功能的不同方式,从客户端的角度来看,这种方式更为简单。

  • 客户端会创建 EVENTPAIR,而不是确定唯一 ID。
  • 客户端可以丢弃事件对的另一端,而不是使用相同的唯一 ID 显式调用 DeregisterBufferCollection。
  • 客户端可以复制事件对的另一端,并在多个 Scenic::Session 中使用该端来创建 Image 资源。

请参阅下文,了解 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 协同使用才能完成的集成测试可以通过转换树内像素测试来完成。

性能注意事项

Allocator API 不会添加任何其他 API 调用。这样可以避免客户端执行 DeregisterBufferCollection 调用。

安全注意事项

Allocator API 依赖于 EVENTPAIR 功能来解决安全问题。EVENTPAIR 的唯一性以及在创建时与其他端点的强关联可确保恶意客户端无法劫持和访问底层缓冲区。如果他们以某种方式获取了 EVENTPAIR,则只能显示此图片,而无法修改或读取它。

缺点和替代方案

Allocator API 提案有两个主要改进要点,其中任一要点都可以由现有协议和流程替换。

  • 我们可以继续使用唯一 ID 来引用缓冲区集合,而不是事件对。我们可以让客户端选择唯一的集合标识符,也可以从注册调用返回唯一的集合标识符。
    • 选择唯一标识符需要同步,无论是客户端查找有效标识符,还是等待分配器确认后再使用标识符,都需要同步。
    • 唯一标识符很容易被恶意客户端盗用。
    • 我们需要显式调用 DeregisterBufferCollection()。
  • 我们可以在 Scenic::Session 和 Flatland 实例中保留 Allocator,而不是公开新协议。
    • 与多个会话一起使用的复杂客户端仍然存在以下限制:无法使用注册的会话以外的缓冲区集合。