Magma:设计

如需简要了解 Magma,包括背景、硬件要求和架构说明,请参阅 Magma:概览

目标

可扩展核心

Magma 旨在尽可能减少在不同的 GPU 和客户端驱动程序设计中,客户端驱动程序与其各自的系统驱动程序进行通信的方式中的架构差异。必要时,Magma 添加了特定于 GPU 的查询、命令结构和接口以满足特定要求。驱动程序专用文档中说明了这些差异。

前馈

主 IPC 通道会尽可能以前馈方式使用,以防止阻塞客户端线程。对于从系统驱动程序发回给客户端的通知,驱动程序定义的消息会异步发送。

避免 GPU 故障

客户端可能会导致 GPU 挂起或发生故障,发生这种情况时,会影响系统关键 GPU 客户端(例如合成器),导致用户体验出现明显的中断。因此,Magma 会尝试尽可能减少客户端诱发 GPU 故障的机会。

架构

如概述中所述,Magma 架构涉及两个驱动程序组件:客户端库和特权系统驱动程序进程。两者都特定于 GPU;客户端库必须从 IR(中间表示法,例如 SPIR-V)将软件编译为机器代码,并正确格式化命令缓冲区以供硬件使用。这些数据被馈送给 Magma 系统驱动程序,由 Magma 系统驱动程序执行实际的硬件编程。

Magma 架构方框图

Magma 为特定于 GPU 的代码定义了两个接口:

  • magma 接口为客户端驱动程序(通常是 libvulkan)提供基础
  • msd(magma 系统驱动程序)接口指示 magma 服务驱动程序实现的入口点

libmagma 是一个便捷层,可实现 magma 接口并将调用适当地转发给 magma_system。magma_system 是一个与 GPU 无关的层,处理驱动程序初始化和拆解、IPC 命令的传输以及一些验证。

因此,Magma 驱动程序的创建大体上可以简化为两个步骤:

  1. 利用 magma 接口生成客户端驱动程序(如下所述)
  2. 实现 msd 接口以生成 magma 系统驱动程序。

如需详细了解构建这两个组件的过程,请参阅移植指南。

Magma 界面

Magma 接口是 Magma 系统驱动程序提供的服务接口。此接口旨在用于实现加速图形 API。它由 magma.h 和 GPU 专用头文件(例如:intel)组成。

在 Fuchsia 上,Magma 包含一个 magma_sysmem.h 标头,客户端可以使用该标头与 sysmem 进行交互。Fuchsia SDK (@fuchsia_pkg//pkg/magma_client) 提供了 Magma 头文件和用于实现这些头文件的静态库。

实体设备

在 Fuchsia 启动序列期间,每个能够加速图形的物理设备都会实例化 Magma 系统驱动程序。实例化会在 gpu 类中创建设备绑定;例如,在单个 GPU 系统中,设备会绑定到 /dev/class/gpu 下的节点。有了适当的应用权限,客户端驱动程序可以扫描是否存在一个或多个 GPU 类设备,然后打开这些设备。您可以对设备文件描述符执行同步查询,以返回各种参数,其中一些参数可能有助于应用决定在哪种配置下处理哪些实体设备。

连接

当应用声明其打算与特定实体设备搭配使用时,便会与 Magma 系统驱动程序建立连接。例如,在 Vulkan 中,通过调用 vkCreateDevice() 来表达使用实体设备的意图。此连接为客户端驱动程序与系统驱动程序之间的所有进一步通信奠定了基础。连接允许客户端驱动程序分配缓冲区并将其映射到 GPU 地址空间。该连接会定义内存隔离边界;Magma 可保证默认情况下,映射到一个连接的地址空间的缓冲区不能由另一个连接访问。通过显式导出/导入,可以在连接之间共享缓冲区。

上下文

如需在 GPU 上执行工作,需要一个上下文。上下文由 Magma 系统驱动程序安排在 GPU 上执行。上下文应包含将多个上下文切换到硬件上所需的所有 GPU 状态。命令缓冲区用于设置 GPU 的状态,因此命令缓冲区会提交到特定的上下文。Magma 支持每个连接使用多个上下文;这允许多个上下文共享一个地址空间。

当客户端连接关闭时,为了避免 GPU 故障,当 GPU 使用该地址空间执行工作时,地址空间必须保持活跃状态;因此,上下文会接受地址空间上的共享引用。

缓冲区和映射

目前,Magma 需要统一的内存架构,就像大多数移动硬件的情况一样,其中 CPU 和 GPU 访问相同的物理内存。Magma 缓冲区只是 zircon 虚拟内存对象 (VMO)。客户端驱动程序会分配缓冲区,并向系统驱动程序注册这些缓冲区。

GPU 地址空间管理可由客户端或系统驱动程序执行。客户端驱动程序设计可以决定模型。

如果系统驱动程序管理缓冲区映射生命周期,则系统驱动程序可确保映射及其底层缓冲区处于活跃状态,而引用它们的命令缓冲区在 GPU 上处于未完成状态。由于映射速度缓慢(因为这需要确保提交缓冲区页面,并且需要修改页面表以引用每个页面的正确总线地址),因此缓冲区映射必须在缓冲区的生命周期内持续存在,或者可以使用 GPU 映射缓存来限制缓存映射占用的内存量。

系统驱动程序管理的缓冲区映射的缺点是,在构建命令列表时,客户端需要知道映射缓冲区的 GPU 地址;因此,命令缓冲区必须先由 Magma 服务驱动程序修补,然后才能执行。因此,最好让客户端驱动程序明确管理 GPU 映射生命周期。显式方法的缺点是,当映射在 GPU 上传输时,客户端可能会取消映射或释放缓冲区;如果发生这种情况,则 GPU 正在使用时,页表条目将失效,这很可能会导致 GPU 故障。

如果每个命令缓冲区都附带一个依赖缓冲区映射的列表,则可以缓解这种缺点;然后,命令缓冲区可以共享 GPU 映射的所有权;如果在资源正在执行时收到取消映射或释放,这会被视为客户端的严重错误,而不会中断 GPU。

命令提交

命令包含特定于供应商的数据,用于修改 GPU 的状态并触发 GPU 计算核心上的代码执行。系统驱动程序负责将提交的命令排入队列,以及将提交的命令安排到 GPU 上以供执行。可以使用各种调度算法:FIFO(默认)、优先级、时间切片。预先占用运行命令缓冲区(如果硬件支持)可用于实现上下文优先级设置。

信号量

Magma 将信号量作为一种通用信号量,可用于实现 Vulkan 栅栏和信号量。Magma 信号量基于锆石事件构建。

对象所有权摘要

  • 客户端:拥有连接;对缓冲区、映射和上下文的共享所有权
  • 连接:共享地址空间的所有权
  • 上下文:地址空间的共享所有权
  • 地址空间:映射的共享所有权
  • 映射:缓冲区的共享所有权
  • 命令缓冲区:共享上下文的所有权;可能同时拥有映射的所有权

线程模型

每个已安装的 GPU 设备和驱动程序使用的线程模型如下所示:

msd 通常由平台总线驱动程序加载,并创建一个 msd 主 devhost 线程。而 msd 主线程会创建一个设备线程来与 GPU 通信,并创建一个与驱动程序相关的中断线程数,以便处理 GPU 中断。

实现 Vulkan API 的客户端驱动程序库称为 vcd(Vulkan 客户端驱动程序)。当 Vulkan 应用启动并创建新的 VkDevice 时,vcd 会向 msd 发出请求,为将要传递所有 Vulkan 命令的设备建立连接。msd 主线程通过创建一个新的连接线程来响应所有客户端命令来响应此调用。连接线程进而创建两个 zircon 通信通道:主通道和通知通道。

Vulkan 状态配置、资源创建和绘制命令缓冲区会通过主通道从 vcd 发送到 msd。通知渠道用于将异步状态消息传送回 vcd。命令缓冲区的完成情况就是 vcd 可能感兴趣的通知的一个很好的例子。通过设备和通知渠道发送的确切消息以及这些消息的处理方式因 GPU 驱动程序而异。

Vulkan 驱动程序线程模型

请注意,封装 msd 的进程边界是 msd 的 Fuchsia devhost 进程边界。此 devhost 进程可能还包含来自其他驱动程序的线程,但此处仅显示了特定于 msd 的线程。

错误处理

当 magma 服务驱动程序中出现错误时,相应的连接会终止。当客户端驱动程序尝试访问已关闭的连接时,通常会传递“设备丢失”Vulkan API 错误。

电源管理

电源管理涉及根据 GPU 负载的测量以及潜在功耗或散热限制来调整 GPU 执行频率。电源管理方面的详细说明将在后续文档中提供。

测试策略

请参阅 test_strategy