RFC-0205:Vulkan 加载器

RFC-0205:Vulkan 加载程序
状态已接受
领域
  • 图形
说明

有关应用如何加载 Vulkan ICD 和层的说明

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2023-01-12
审核日期(年-月-日)2023-01-12

摘要

本 RFC 介绍了 Fuchsia 上的软件如何加载 Vulkan ICD图层来执行硬件加速渲染。

本文档中的系统已经基本实现, 文档中可能会包含我们打算在 。

设计初衷

Vulkan API 具有 C 风格的接口,应用可使用该接口进行编程 GPUVulkan 应用使用 Vulkan 与 Vulkan 功能进行交互 加载器通过 API 接口与 Vulkan 函数

在本文档中,“应用”用于表示使用 Vulkan API。

Vulkan 加载程序还负责加载可安装的客户端驱动程序 (ICD) 和 Vulkan 层,同时授予对 magma 或其他 代表 ICD 执行 GPU 命令所需的 API。

Vulkan ICD 是加载到 使它们能够使用 GPU 进行渲染使用 Vulkan 需要一种机制来识别和加载 系统。

Vulkan 层是共享库,用于修改或观察 Vulkan API。它们可以是 用于增强 Vulkan 的功能或代表 Vulkan 调试或性能分析功能。

利益相关方

教员

rlb@

审核者

cstout@ costan@ jhowarth@ msandy@ rosasco@ palmer@ wittrock@

已咨询

社交化

设计已经过 Magma 团队成员的审核。早期 此文档的版本已共享至组件框架 以及安全团队咨询交流时间。

设计

在 Fuchsia 上,Vulkan 加载器分为两部分: 加载到应用中的 libvulkan.so 共享库。 以及一个负责vulkan_loader 加载 ICD VMO 并将其传输到 libvulkan.so。它们使用 fuchsia.vulkan.loader.Loader 协议。

libvulkan.so

Khronos 是 Vulkan API 的标准正文。它们提供 Linux 上使用的 loader 共享库实现, Windows、macOS 和大多数其他平台。Google 编写了一个单独的加载器以供使用, 。

Fuchsia 加载器基于 Khronos 的实现;代码位于 third_party/Vulkan-Loader,但最终 都将传送到上游。当应用调用 vkCreateInstance 或其他枚举函数后,加载器 会读取环境变量和 JSON 配置文件,以确定 要使用的 ICD 和图层集。层从组件的 命名空间,因此它们通常存储在 包内。它们也可能被 从提供给组件的目录功能加载的 加载器配置设置为使用这些目录。

ICD 加载

Vulkan 加载器启动
流

启动时,libvulkan.so 会连接到 fuchsia.vulkan.loader.Loader 协议。此频道必须 在整个应用生命周期内保持连接状态。如果退出, 加载器调用可能会失败。

这种长期连接可防止组件框架重新加载或 在使用 Vulkan 的客户端运行时,更新加载器。这是 非常理想,因为它可以防止对 Vulkan ICD 的版本进行意外更改 和加载器接口。部分 用于枚举扩展或其他实例属性的 Vulkan 入口点 不接受任何类型的 context 参数;因此该实现将具有 某种隐式全局状态

Vulkan 加载程序
流

ICD 使用 fuchsia.vulkan.loader.Loader 协议加载。加载器 使用 fuchsia.vulkan.loader/Loader.ConnectToManifestFs 方法访问 包含清单 JSON 文件,用于说明 ICD;此文件系统看起来与 /usr/local/share/vulkan/icd.d Linux 上的文件系统请参阅文件系统服务 该文件系统的详细信息

然后,加载器将使用 fuchsia.vulkan.loader/Loader.Get 方法获取 检索与 ICD 对应的 VMO,可通过 dlopen_vmo 命令将其加载到 并从中获取 ICD 入口点。该组中的 Vulkan 入口点 Fuchsia 与 Linux 上的基本功能相同,但前者具有特定的 Fuchsia 扩展, 如下所述。

客户端组件还可以与软件 ICD 实现(如 SwiftShader.对于 SwiftShader,VK_ICD_FILENAMES 环境变量可用于指定指向 manifest.json ICD。系统将从 Vulkan 的 /pkg/lib 加载 ICD 共享库 客户端组件。

由于大多数 ICD 未存储在软件包中,而是与 应用二进制文件,那么他们只能对应用二进制文件的 ABI 做出有限的假设 链接到的应用它们可以依赖的确切接口是 Fuchsia 系统界面中列出的样式,但通常情况下 只能使用一定数量的符号,这些符号必须全部来自 libc.solibzircon.so。构建 ICD 时,导入的符号 已根据 许可名单至 确保 ICD 可针对多个版本的客户端进行加载 应用。未来,此许可名单可能会缩减为封闭的替代品 资源。

ICD 需要能够连接到外部协议;特别是 连接到与硬件通信的底层设备驱动程序。他们 可能还需要读取供应商专用的配置文件 错误。libc.so 会导出几个符号以执行 I/O,但实际上, 底层操作(例如 open)是在 libfdio 中实现的。此外, 必须使用文件系统,才能连接 Zircon 通道, 直接从 libfdio 导出的其他符号。

为了允许 ICD 执行有限的 I/O,这些定义已添加到 Vulkan ICD 中 API:

VkResult(VKAPI_PTR* PFN_vkOpenInNamespaceAddr)(const char* pName, uint32_t handle);
VKAPI_ATTR void VKAPI_CALL vk_icdInitializeOpenInNamespaceCallback(PFN_vkOpenInNamespaceAddr
open_in_namespace_addr);

ICD 应公开 vk_icdInitializeOpenInNamespaceCallback。早于 其他驱动程序函数被调用时,该函数将使用 open_in_namespace_addr 回调。ICD 可以传递文件名和 Zircon 通道客户端连接到此回调,以按名称连接到文件系统节点。

此函数可以访问进程的传入命名空间,因此 ICD 可以 读取配置文件或连接到 fuchsia.logger.LogSinkfuchsia.tracing.provider.Registry。Vulkan ICD 可能包含全局状态,因此如果 该进程是一个运行程序,可以托管多个子组件(可能由 使用虚拟机或其他非进程机制来隔离组件), 运行程序必须确保向 ICD 提供的服务可在任何 子组件。例如,如果有多个不受信任的子组件 位于同一进程中,运行程序不应路由 通过运行程序指定的子组件 fuchsia.tracing.provider.Registry 因为该组件可能会窥探所有 ICD 图形活动。

在特殊情况下,open_in_namespace_addr 回调会访问 /loader-gpu-devices 路径。对该路径的所有访问都会路由到文件系统 使用vulkan_loader fuchsia.vulkan.loader/Loader.ConnectToDeviceFs 方法;这样 ICD 就能够 连接到所需的任何特定于硬件的设备驱动程序节点。ICD 可以使用 zxio 或原始 FIDL(用于遍历文件系统);请参阅文件系统 提供相关文件系统的详细信息。

图层通常通过 SDK 分发,并从同一个 因此它们可以依赖于 SDK 中的软件。通过目录加载的图层 外部功能包中的功能应被视为与 ICD 相同 属性。

ICD 卸载/重新装载

目前还无法卸载共享库,因此将保留所有 ICD 在进程的生命周期内一直加载。在创建 新的 Vulkan 实例,加载器保留其所有 ICD 的无过期缓存 看到过(由共享库文件名标识)。此文件名对于 只要 vulkan_loader 连接处于活动状态。

加载器执行环境

Vulkan API 没有异步运行循环的概念,因此函数调用 必须同步完成。加载器 未收到来自应用的 async_dispatcher_t*,因此是不允许的 以使用 libasync-default.so 中的默认调度程序。它可能会自行创建 调度程序和线程。

组件的传出目录由应用程序的代码托管,因此 无法在其中放置条目。这会限制它与 其他组件应用所需的平台也并非 只加载该加载器的一个副本,尽管当前所有应用都使用 从 libvulkan.so 复制,由于其 Soname,将在加载时删除重复信息。

默认情况下,该加载器在 /vulkan-loader-configuration,回退到 /pkg/data。这些路径可以是 被环境变量或替换层覆盖,则 与在 Linux 上相同

vulkan_loader

vulkan_loader 是一项负责确定哪些 ICD 的服务 加载它们并提供给应用托管于 /core/vulkan_loaderfuchsia.vulkan.loader.Loader 其公开的服务被路由到会话、测试框架和 应用。它使用 C++ 编写,代码位于 //src/graphics/bin/vulkan_loader,文档位于 /src/graphics/bin/vulkan_loader/README.md.

未来,此服务可能会重写为 Rust,以降低安全风险和 充分利用异步编程功能

识别新设备

vulkan_loader 服务必须能够识别哪些 ICD 是可用的。这个 由一组正在运行的设备驱动程序驱动。如果设备驱动程序 如果没有针对硬件运行,则与其相关的 ICD 就不可用。

vulkan_loader/dev/class/goldfish-pipe 上使用目录观察器, /dev/class/gpu 来确定何时出现新的图形设备。

当新的图形设备出现时,加载程序必须确定该组件。 ICD 的相关规定。具体机制取决于设备类型:

  • /dev/class/gpu - 调用 fuchsia.gpu.magma/Device.GetIcdList
  • /dev/class/goldfish-pipe:ICD 网址经过硬编码,成为 fuchsia-pkg://fuchsia.com/libvulkan_goldfish#meta/vulkan.cm

未来可能会支持更多类型的 GPU 硬件设备。软件 ICD 还可能在某些设备上通过加载程序协议公开,作为后备 (由 vulkan_loader 配置选择)。软件 Vulkan ICD(例如 SwiftShader) 通常具有 JIT,并且需要能够写入可执行文件 内存;因此它们可能无法用于 功能受到严格控制。

文件系统传送

vulkan_loader 为客户端提供多个文件系统,包括清单 fsdevice fs。它会根据文件内容 并通过 devfs 接收多个 ICD 软件包和服务。因此,他们 必须使用文件系统服务库进行构建,且不能反映 以及磁盘上的任何内容

  • manifest fs:所有清单文件 JSON 文件,描述 相关 ICD;这个文件系统看起来与 /usr/local/share/vulkan/icd.d(在 Linux 上),以便对加载器进行极少的更改 所需的资源。
  • device fs:包含支持的 Vulkan ICD 所需的所有 GPU 设备。对于 /dev/<path>/<node> 设备,则文件系统中将包含 <path>/<node> 条目。

ICD ↗︎加载程序界面

ICD 作为 CFv2 组件提供给加载程序。ICD 组件必须公开一个 contents 目录,其中包含任意 包含共享库以及 metadata 目录的目录树 包含单个 metadata.json 文件。

ICD 通常单独包含在单独的软件包中。在这种情况下 contents 目录将是软件包的根目录,而 metadata 目录为软件包中的 meta/metadata/ 目录。加载器 不过,它不会强制执行此布局。

metadata.jsonmanifest.json 最好存储在 meta 下 目录,因为该目录在 存储小文件的方法。

ICD 共享库

ICD 共享库应与 Vulkan ICD ABI 匹配。ICD 是 可执行的共享库,并且可以放在大多数的子目录(而不是 /bin)。

组件清单

Vulkan 加载器提供了一个 icd_runner 运行程序,以简化 文件包中的 ICD 组件ICD 包必须包含组件 manifest .cml,用于导出 contentsmetadata。 目录功能

icd_runner 会自动导出 /pkg/data/pkg/meta/metadata /pkg-data/pkg-metadata 路径下 ICD 软件包中的目录。 CML 可以使用这些文件导出这两种目录功能(使用 subdir 属性将子目录作为完整功能公开)。

ICD 组件也可能使用 ELF 运行程序,但这是唯一可用的服务 其为 fuchsia.logger.LogSink

metadata.json

metadata.json 是单个 JSON 文件,用于向加载器描述 ICD。 示例:

{
    "file_path": "lib/libvulkan_example.so",
    "version": 1,
    "manifest_path": "meta/icd.d/libvulkan_example.json"
}
  • 对于此元数据版本,version 必须为 1。
  • file_path 是 ICD 共享库相对于公开库的位置 contents 目录中。
  • manifest_pathKhronos ICD 清单 JSON 的位置 file(相对于公开的 contents 目录)。

其他客户端

可用的 Vulkan ICD 集可能会随时间而变化;系统首先 启动后,在硬件枚举之前,没有可用的 ICD。之后 设备可能会热插拔并出现或消失。

这意味着,vkEnumeratePhysicalDevices 返回的设备列表可以 更改。某些需要 Vulkan 的应用可能需要重试 在一组可用设备发生变化后自动应用他们可以使用文件系统监视器 从 fuchsia.vulkan.loader/Loader.ConnectToManifestFs 返回的文件系统 以确定何时重试。

实现

此设计代表了 Vulkan 加载器的当前架构,如同 在 Fuchsia 上实现的。

性能

Vulkan 加载器在进程启动时最活跃。Vulkan ICD 后 它会 trampoline Vulkan 调用以进入 ICD 中,或返回 ICD 函数实现到应用以供应用调用 。因此,其性能仅在进程启动期间才至关重要。

没有特别考虑加载器的性能。它具有 启动组件以连接到 ICD 并遍历多个文件系统路径 确定 ICD 和层配置目前还不相信 以确保它对运行时性能有重大影响。

向后兼容性

libvulkan.so 和 vulkan_loader 之间的通信使用文件系统、JSON 和 FIDL。文件系统和 JSON 已经在 Linux 上使用了好几年 而不会出现向后兼容性问题你可以通过多种自然方式 (分别添加路径和键)以保持向后兼容性。通过 FIDL 接口很小,可以使用 FIDL 版本控制机制改进。

安全注意事项

组件将加载 Vulkan 加载器提供的共享库。通过 系统正常的验证执行强制执行将确保 可执行的共享库来自可信位置(例如 文件系统)。任何父组件都可以插入 fuchsia.vulkan.loader.Loader 协议,因此无法保证加载器 服务组件看到的内容由系统提供。

选择要加载的 ICD 由 Magma 系统驱动程序中的路径引用 (MSD) 并通过解析器加载。默认使用完整解析器 以便加载临时软件包从临时软件包加载 ICD 为 对 ICD 开发者很有用,但对大多数用户来说都不是必需的。 您可以通过停用完整解析器来停用加载临时软件包 (设置 auto_update_packages=false gn 参数)。我们也可以创建多个 产品所有者可以选择的 Vulkan 加载器的核心碎片;互动 build 可以选择使用完整解析器的分片,用户 build 则可以 将分片与基本解析器一起使用。

如果需要特定商品,可以添加 vulkan_loader 的多个实例 服务,且每个服务都可以访问不同的解析器。他们的 可将“fuchsia.vulkan.loader.Loader”实现路由到客户端 所依据的要素安全要求目前不能 有此要求。

配置加载器可能会导致应用出现意外行为, 加载新图层、阻止加载其他图层,或设置选项 。组件必须选择接受其配置, (方法是从 软件包),但在其他方面完全控制加载器配置。

ICD 共享库在客户端进程中执行,并且可以执行 任意代码。构建流程和一致性测试 确保它们仅导入列入许可名单的符号,但这无法保证安全 并可能很容易被查看调用堆栈来查找地址 解析内存中的可执行文件以查找有用的小工具。应用不会 用于验证 Vulkan 返回的大多数值,并且可能会被操纵 通过谨慎操作这些值访问任意内存。

如果运行程序将它不信任的多个组件加载到单个进程中 (比如使用虚拟机或其他非进程机制将 组件),这些组件必须能够进行直接 Vulkan 调用, 因为尚无任何已知方法来验证 Vulkan API 调用, 应用不会在 Vulkan ICD 中执行未定义的行为;甚至 Vulkan 验证层仅提供有限的保护。运行程序代码可能会使 Vulkan 调用自身,例如使用 Skia 或 ANGLE 执行经过验证的渲染 来代表客户端运行命令您向 ICD 必须来自运行程序信任的某个来源,以防止子组件 相互窥探。

隐私注意事项

Vulkan 加载器对隐私的影响微乎其微。通过这些链接 FIDL 决定了应用是否会尝试使用 Vulkan,以及它会使用哪些设备 资源。

测试

vulkan_loader 和 libvulkan.so 进行单元测试和集成测试。这些测试 是封闭的,不依赖于 系统。

此外,还有 CTF 测试,以确保 fuchsia.vulkan.loader.Loader 协议是否正确,并且由 它与旧版加载器兼容。

紫红色树中的 Vulkan CTS 和其他 Vulkan 测试充当端到端 测试,检查 vulkan_loader 是否与 libvulkan.so 兼容。 这些只能在具有 Vulkan 硬件和设备驱动程序的系统上运行。

文档

我们在以下位置提供了 vulkan_loader 份文档: /src/graphics/bin/vulkan_loader/README.md.有一位用户 文档,了解如何使用 Vulkan 加载程序。

上游 Vulkan 加载器包含相关文档。我们应该尝试 向该文档添加并上游传送 Fuchsia 特定信息。

先验技术和参考资料

Linux/Windows/MacOS 加载程序