RFC-0198:Magma API

RFC-0198:Magma API
状态已接受
区域
  • 图形
说明

GPU 和其他计算加速器的驱动程序 API 设计。

Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-09-19
审核日期(年-月-日)2022-11-01

摘要

Magma 是 Fuchsia 的 GPU 驱动程序设计。它还可用于支持其他硬件计算加速器。此 RFC 是 Magma FIDL 协议的 API 设计文档。

Magma 有两个驱动程序组件:加载到每个应用的地址空间中的特定于硬件的库(“客户端驱动程序”,有时称为“可安装的客户端驱动程序”或“ICD”);以及与硬件交互的 Magma 系统驱动程序。两个“驱动程序”之间的通信由 Magma 协议定义。

在本文档中,“应用”用于表示使用客户端驱动程序公开的 API 的软件组件。

设计初衷

Magma API 提供了一种解决方案,用于在 Fuchsia 系统上支持硬件加速的图形和计算 API(主要是 Vulkan)。其 API 概念并非特定于 Vulkan,因此可减少支持其他客户端 API(例如用于视频的 VA-API、OpenVX 和 OpenCL)的摩擦。

Magma 旨在供 Vulkan API 的实现使用。Vulkan 是 Fuchsia SDK 中提供的 C 样式 ABI。这些实现(“ICD”)通常由硬件供应商开发,因为加速器硬件庞大而复杂,并且构建实现需要详细的硬件编程知识。

由于应用可以直接使用 Vulkan,因此 ICD 是由系统提供的库,但无法访问硬件。使用 Magma,ICD 可以与加速器硬件交互,以满足 Vulkan API 的要求,而这些要求主要包括执行客户端定义的程序。

Magma 系统驱动程序 (“MSD”) 通过在硬件上调度和执行客户端请求来实现此协议的服务器端。因此,Magma 旨在连接 ICD 和 MSD,在 Linux 上发挥与 DRM(直接渲染管理器)类似的作用。

Magma 的目标是切实地最大限度减少 API 中特定于供应商的方面。这样可以更轻松地推理 API 安全性,并有助于对驱动程序进行安全审核。

Magma 提供了一组常用的核心 API 功能和方法,而不是让每个 GPU 供应商都设计自己的 ICD-MSD 接口(这在 Linux 上很常见)。在必要时,Magma 允许使用特定于供应商的查询和命令结构。Magma 定义中未包含供应商特定信息,但驱动程序特定文档中对此进行了说明。

支持显示硬件不是目标。

Magma API 目前在生产环境中被三个驱动程序使用。由于 Fuchsia SDK 中没有相应 API,因此这些客户端驱动程序的 build 和发布流程非常复杂。

在所有当前情况下,使用的客户端库可促进与 C 代码库的集成(C 是 Mesa 中的首选语言,可提供许多开源图形驱动程序),并为虚拟化提供便捷的抽象层。审核和可能纳入 SDK 的客户端库是未来的工作。

利益相关方

辅导员

不适用

审核者

jbauman@、rlb@:硬件图形

已咨询

API 委员会

共同化

不适用

设计

Magma 有三种协议,定义如下:

https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/sdk/fidl/fuchsia.gpu.magma/magma.fidl

有些名称带有数字后缀(例如 BufferRangeOp2);该数字是协议演变的详细信息,可以忽略。

  1. 设备

在 Fuchsia 启动序列期间,系统会为每个能够进行加速图形和/或计算的物理设备实例化一个 Magma 系统驱动程序。如果应用具有适当的权限,客户端可以扫描是否存在一个或多个“gpu”类设备,并打开这些设备。可以通过设备协议执行同步查询,以获取有助于应用决定在何种配置下使用哪些物理设备的参数。查询参数还用于确定哪些类型的 ICD 与每个 GPU 设备兼容。驱动程序专用协议和设备专用协议的确切行为将取决于这些查询参数。

当应用声明其打算与特定实体设备搭配使用时,系统会与 Magma 系统驱动程序建立连接。例如,在 Vulkan 中,通过调用 vkCreateDevice() 来表达与物理设备交互的意图。此连接构成了客户端驱动程序与系统驱动程序之间所有后续通信的基础。

连接包含两个渠道。主渠道用于主协议,主要是在客户端-服务器方向,而另一个渠道用于从服务器到客户端的通知。

  1. 主要

主要协议包含少量通过前馈设计实现的核心功能。错误会触发墓志铭消息,然后关闭连接渠道。

a) 导入共享资源、缓冲区和事件 (ImportObject, ReleaseObject)

缓冲区是由 Zircon VMO 支持的共享内存对象。Zircon 事件可用于 API 需要信号量的同步。

对象由客户端分配,并通过其 KOID(内核对象 ID)引用。客户端分配是一种前馈设计选择。这假设所有缓冲区都来自系统内存,这对于移动类硬件通常是正确的。

未来对具有专用内存的桌面级 GPU 的支持可能需要进行 API 更改。

未来对外部 Vulkan 时间轴信号量的支持可能需要导入一种新的内核对象。

b) 映射缓冲区 (MapBufferGpu、UnmapBufferGpu、BufferRangeOp)

为了让硬件能够访问缓冲区,必须将缓冲区映射到设备地址空间。每个客户端连接都分配有专用 GPU 地址空间(请参阅“安全和隐私”),因此 Magma 希望设备地址空间管理由客户端执行。

对于某些驱动程序,MapBufferGpu 可能意味着在设备 MMU 中填充页表,而对于某些驱动程序,则支持通过缓冲区范围操作显式控制页表填充。

页面表的填充意味着缓冲区页面的提交。任何客户端页面取消提交操作都应通过适当的取消填充操作与系统驱动程序协调。

c) 创建执行上下文(CreateContext、DestroyContext)

若要在硬件上执行工作,需要一个上下文。上下文包含所需的所有硬件状态,以便将多个上下文切换到硬件上,并由 Magma 系统驱动程序安排执行。Magma 支持每个连接有多个上下文;这使得多个上下文可以共享一个地址空间。

d) 执行命令(ExecuteCommand、ExecuteImmediateCommands)

命令包含供应商特定的数据,这些数据可修改硬件的状态并触发加速器计算核心上的代码执行。程序代码由应用提供给客户端驱动程序,通常采用与机器无关的格式(例如 SPIR-V)。客户端驱动程序必须将代码转换为加速器硬件可理解的机器级指令。

Magma 提供了两个用于执行命令的接口:

ExecuteCommand 假定程序代码和关联资源包含在共享缓冲区中。通过等待信号量列表(在安排工作之前必须发出信号)和信号量(在命令完成时发出信号)提供同步。

ExecuteImmediateCommands 会内联发送命令。如果驱动程序定义了拆分多个命令的方式,则可以在单个渠道消息中包含多个命令。每条消息的命令字节数目前限制为 2k,这是一个任意限制,到目前为止效果良好,但无法有效利用完整的渠道消息大小。系统提供了可用于等待或发出信号的信号量,具体取决于关联的命令数据。

未来考虑的命令提交方式包括:使用带有临时 VMO 的 fuchsia.mem.Data,或使用 Linux“io_uring”等模型:https://en.wikipedia.org/wiki/Io_uring

e) 流控制

为防止客户端将过多消息推送到主渠道,并防止主渠道中待导入的缓冲区对象过度使用内存,设备协议会发布最大值,而主协议会规定客户端保留计数,并延迟发送消息以使这些计数小于发布的最大值。服务器提供事件消息,以告知客户端何时可能会减少计数。

f) 性能计数器

主协议公开了许多专门用于与硬件计数器交互的 API,这些 API 对于应用深入了解在加速器硬件上运行的程序的行为和性能特征至关重要。

  1. 通知

通知渠道用于仅以反向(服务器-客户端)发送的消息,通常用于响应命令完成。通知消息的内容往往因供应商而异,因此我们定义了一个空协议。

与主渠道分开的通知渠道可让客户端更轻松地处理通知事件,例如,客户端可以使用专用线程。在主渠道上,客户端调用可能来自多个线程,其中没有任何循环在异步调度程序中进行轮询,出于性能考虑,我们不希望将这些调用代理到主渠道中。这使得读取异步事件变得困难(除了只需要在发送消息期间读取的流量控制事件)。

未知

目前有 4 个受支持的 Magma 驱动程序(其中 3 个处于正式版阶段),另外 2 个已完成原型设计。每次启动额外的 Magma 驱动程序都会提供更多信息,以便了解 Magma 协议是否适合替换各种现有的基于 Linux 的客户端驱动程序-内核驱动程序接口。添加对桌面级 GPU 的支持,有助于确保核心 API 与各种硬件兼容。

需要改进的 API 领域主要是:命令执行和通知处理。

我们非常欢迎 API 委员会就以下主题提供反馈:

a) 这些 API 与其他 Fuchsia API 有何相似之处或不同之处? b) 有没有机会让这些 API 更具未来性? c) 您认为 io_uring 模型对 Fuchsia 有何用处?

Google 的领域专家已对该 API 进行简要审核;不过,如果能进行更全面的审核,并让 Google 的其他专家/相关团队参与其中,可能会更有益。

性能

设备协议包含同步方法,但这些方法仅应在应用的设置阶段使用。主协议包含异步方法,命令完成情况通过通知渠道以异步方式返回。

大多数数据都在 VMO 中共享,因此数据复制量会降至最低。创建和映射缓冲区可能很慢,但假设应用设计良好(例如,执行内存子分配),这些操作应该很少发生。

在大多数情况下,Fuchsia 上的 Magma 驱动程序的性能与在同一硬件上运行的相同客户端驱动程序代码库在 Linux 上的性能相当。

人体工学、可用性

该 API 设计与已研究过的现有基于 Linux 的客户端驱动程序-内核驱动程序接口类似,不同之处在于,分配尽可能在客户端执行。

我们认为该 API 的语义相当直观,因为该 API 已使用两年,在此期间经过了修订,目前正在为来自不同供应商的三个生产驱动程序提供服务。

未来,对于 Vulkan 时间轴信号量,可能需要新的内核对象;如果需要,则可能会将其添加到 ObjectType,并且在执行 API 中通过 KOID 指定信号量的情况下,可能会引用“时间轴”对象来代替事件。

向后兼容性

在预计未来需要进行扩展的各种位置,都使用了 FIDL 表。

安全

Magma API 允许应用在重要的共享系统资源上运行未经验证的程序,因此安全性是一个重要主题。已于 2021 年 6 月完成安全审核:请参阅 https://fxbug.dev/42146613。

客户端可能会提交长时间运行的程序,从而拒绝其他客户端访问硬件。Magma 系统驱动程序可确保长时间运行的程序在系统中断程度可接受的情况下中止,与其他系统的行为类似。

显存可能包含密码等敏感信息,因此隔离客户端的内存访问非常重要。客户端连接通过独立的硬件地址空间相互隔离:也就是说,客户端的程序只能访问已导入到连接的内存缓冲区(由客户端创建或从外部显式接收)。这种方法可能会受到硬件漏洞的影响。

客户端数量可能超过硬件提供的地址空间数量。MSD 应安排对这些资源的访问权限,或完全拒绝客户端。

出于性能方面的考虑,验证客户端命令和程序并不实际,因此硬件应具有弹性。

隐私权

通过查询 DEVICE_ID 获得的设备 ID 通常不是唯一的。

性能计数器事件可用于确定系统上其他工作负载的一组详细统计信息,这些信息可用于识别其他进程正在执行的操作。因此,它们比大多数 Magma API 受到的限制更多,并且仅限于可以访问 /dev/class/gpu-performance-counters 设备的进程集。

测试

下面提供了一个简单的 API 功能测试:

https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/graphics/lib/magma/tests/integration/test_magma_fidl.cc

如果不包含硬件细节,很难编写更复杂的测试来使用 Magma API。客户端驱动程序代码包含这些硬件编程详细信息,因此执行客户端驱动程序公开的 API 的测试套件至关重要。

在持续集成中测试了两个正式版 Magma 驱动程序的 Vulkan 一致性测试。 OpenVX 一致性测试在适用于 ML 的 Magma 驱动程序上运行。

请注意,在构建 Magma 驱动程序时,开发者应先构建一个实现 Magma 协议服务器端的实用 Magma 系统驱动程序,然后才能测试使用 Magma API 的客户端驱动程序代码。

文档

文档与 FIDL 定义内嵌在一起。

缺点、替代方案和未知因素

此设计与旨在最大限度减少驱动程序开销并最大限度提高系统图形性能的 Vulkan 同步。该设计的缺点是,在安全性方面,它很大程度上依赖于硬件,而替代设计可能会尝试提供客户端命令的验证。不过,验证过程复杂且不完美,可能会带来高昂的性能成本。

在先技术和参考资料

Linux GPU 驱动程序开发者指南:https://www.kernel.org/doc/html/v4.18/gpu/index.html