> For the complete documentation index, see [llms.txt](https://freebsd-journal-cn.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://freebsd-journal-cn.bsdcn.org/20141112-shi-pin-qu-dong-cheng-xu/video-drivers.md).

# 视频驱动程序

## 图形栈之战：视频驱动

* 原文：[Video Drivers](https://freebsdfoundation.org/our-work/journal/browser-based-edition/video-drivers/)
* 作者：**Jean-Sébastien Pédron**

图形栈是一组应用程序、库和驱动，让你能在工作站上显示桌面，或渲染出两小时前你正打算关掉的那款精美游戏——这是我们最容易想到的角色。

还有一些不那么明显的角色，比如在 GPU 上运行计算任务（“GPGPU”，即图形处理器上的通用计算）、处理各种输入设备，甚至提供让计算机对所有人都可用的工具和机制。

因此图形栈的职责远不止字面上的“图形”二字。

FreeBSD 在这个复杂的世界中处于什么位置？我们面前有哪些挑战？先倒一杯美味的 Pauillac 红酒吧！

### 2014 年 X.Org 开发者大会

“能把那瓶 Château Franc Cros 递给我吗？”

“这瓶 Château Altimar 很不错！”

“那个怎么念？”

“干杯！”

10 月 10 日星期五傍晚，我们聚在法国波尔多的“Aux 4 coins du vin”酒馆，品尝着极好的红白葡萄酒，聊着过去三天的会议，更重要的是，共度了一段美好时光！

这场品酒活动和次日参观 Saint-Émilion 为 2014 年 X.Org 开发者大会（XDC）画上句号。这一每年举办、在欧洲与北美之间交替举行的会议，是所有关注自由开源图形栈的人的聚会场所。今年的 XDC 于 10 月 8 日至 10 日在法国西南部的波尔多大学举行。

报告内容精彩，涵盖输入处理与无障碍访问、各视频驱动的进展、X.Org 与 Wayland 的近期变更、以及如何改进安全等话题。今年首次设立了 BSD 专场！议程已在线发布，并附有演讲的幻灯片和视频链接。

我有幸参加这次会议并代表 FreeBSD 项目。星期五上午，François Tigeot、Matthieu Herrb 和我分别介绍了 DragonFlyBSD、OpenBSD 和 FreeBSD 上的图形栈现状。但我的主要目标是结识图形栈背后的开发者，让他们看到 FreeBSD 仍然关心这件事。

这件事之所以必要，原因有二：

第一，可用的图形栈对留住老用户、吸引新人都至关重要，因为 FreeBSD 能在工作站上运行。即便 FreeBSD 并不瞄准“桌面市场”，初级系统管理员也倾向于在生产机上部署与工作站相同的操作系统——主要是因为他们用着顺手。系统管理员也可能想在一台闲置电脑上装上 FreeBSD，先玩一玩，再迁移所有 Web 服务器。老用户的习惯难以改变：笔记本和服务器用同一套工具总是顺手。

第二，可用的图形栈对于利用 GPU 高算力和并行性来执行计算任务这一新趋势同样至关重要。这不仅适合在本地挖虚拟货币，也适合在大型集群上挖。

如今图形栈的大部分开发由 Linux 社区和投资 Linux 的公司完成，所以他们只针对 Linux 也是理所当然——要么是受雇开发，要么是业余为乐。我很高兴地报告，重启与 X 开发者关系的目标取得了巨大成功！大家都很友善热情，对 BSD 总体上表现出兴趣，甚至主动提供帮助。现在该轮到我们努力了！

### 视频驱动

在我们面前的诸多挑战中，视频驱动处于核心位置。驱动分为三部分：内核、Mesa 和 X.Org 的“DDX”（xf86-video-\*）。

驱动的话题太多，本文仅限于讨论我们需要在内核和 Mesa 上解决的部分问题。其他问题正在推进，后续文章会讨论其他方面。

作为铺垫，本文先介绍一些概念。XDC 的报告已发布在图形团队博客上，这里不再赘述。

### 内核视频驱动

为什么需要内核驱动？从 FreeBSD 9.1-RELEASE 和 2012 年的 i915 GPU 开始，视频驱动从用户态迁移到了内核。2013 年，Radeon GPU 驱动加入。这是图形栈完全位于用户空间 25 年后的重大转向。为什么突然改弦更张？

XFree86 时期（后来分叉为 X.Org 项目），X server 是个庞然大物——它执行着通常归内核负责的任务，提供着同样的服务。它扫描总线、驱动输入和视频设备、管理显存，还试图处理安全问题。X Window System 比 Linux 或任何 BSD 都更早问世。包揽一切的目的是保证在所有类 UNIX 操作系统上的可移植性。

这种设计有许多缺点：

* 代码库庞大，维护困难，且其中很多服务内核已经提供。
* 内核和 X server 都在管理总线和设备，比如这让挂起/恢复无法正确实现。
* 为此 X server 需要以 root 权限运行。Xorg 可执行文件设了 setuid，让普通用户也能启动 X 会话。
* 性能低下，主要原因是用户态与内核态之间频繁通信。
* 没有 X server 运行就无法使用 GPGPU，因为硬件由 X server 管理。
* 驱动无法被 Wayland 等其他项目复用。
* 无法在虚拟环境中使用 GPU。
* 在控制台与 X 之间切换时——无论是启动/退出 X 会话还是按 Ctrl-Alt-Fx——都会导致屏幕闪烁。
* 这常常导致内核调试器无法正常工作，获取核心转储不可靠。

这一时期出现了一个可选子系统——直接渲染管理器（Direct Rendering Manager，DRM），它包含一小部分驱动。FreeBSD 中代码位于 **sys/dev/drm**。早期 DRM 只是一种优化，并未解决上述问题，因为所有重要代码仍在 X.Org DDX 中。将 GPU 驱动整体迁到内核 DRM 子系统能解决所有这些问题。但这把担子压到了内核开发者身上，没有持续维护，各操作系统之间的支持程度参差不齐。幸运的是，这些驱动保留了 MIT/X11 许可证，我们可以拿 Linux 驱动来移植到 FreeBSD。

### DRM 子系统

DRM 向用户态应用提供 API，用于向 GPU 发送命令和数据，并从 GPU 读回数据。它包含以下组件：

* DRM 本身，为用户态应用和该子系统的其他组件提供设备无关的功能。
* TTM 和 GEM 是两个内存管理器，负责管理系统内存和显存中的对象、对象在两者之间的迁移、内存映射、分页和交换。
* 驱动本身。撰写本文时我们有两个驱动：i915 驱动依赖 GEM 内存管理器，Radeon 驱动依赖 TTM。

### 维护 DRM

FreeBSD 中 GEM 内存管理器和 i915 驱动的初始移植，基于位于 **sys/dev/drm2** 的旧 DRM 子系统副本。缺失的设备无关代码按需添加，原始 Linux 代码改用 FreeBSD 原生设施（内存分配、锁原语、I²C API、设备管理 API 等）。移植 TTM 内存管理器和 Radeon 驱动时沿用了同样的方法。

好处是代码对 FreeBSD 开发者来说看着眼熟，更容易理解。坏处是这拖累了 DRM 子系统的维护，因为来自 Linux 的新代码必须重新移植。

驱动是图形栈的关键。我们急需一份与时俱进的 DRM 子系统，因为：

* 支持更新的硬件，如 Intel Haswell GPU，它几乎已经准备好进入 FreeBSD；
* 提供新服务，如 DRM PRIME，允许在多个 GPU 与用户态之间迁移数据。

如今我们很难让这一子系统与 Linux 保持同步，而用户态应用已经开始依赖我们尚不具备的特性。一个好例子是 i915 驱动中的硬件上下文支持。该特性为 Mesa 9.2 所必需，而 Mesa 9.2 又被 X.Org server 1.15 所需。此外，Radeon GPU 在 Mesa 10.x 中支持好得多。不幸的是，硬件上下文支持仅在 FreeBSD 10.1-RELEASE 才加入，这意味着旧版 FreeBSD 只能用 Mesa 9.1。因此，我们当前最大的挑战是找到一种更好的方式来维护这个 DRM 子系统。

### 使用 Linux API 垫片

Infiniband 驱动通过嵌入 Linux API 垫片（位于 **sys/ofed/include/linux**）解决了类似问题。这层垫片要么在 FreeBSD 原生接口之上暴露 Linux API，要么直接实现 Linux 设施。借助这层封装，Infiniband 驱动与面向 Linux 的原始代码库保持接近。

我们可以在 DRM 子系统中采用类似方式，做自己的垫片。DragonFlyBSD 就是这么做的，事实证明它在极短时间内带来了 Intel Haswell GPU 支持。尽管我喜欢这种做法，但我更希望有一种集中化、由各驱动共享的方案，这显然能降低维护成本。然而 Linux API 是出了名的移动靶，原因有据可查。走这条路就要回答：如果多个驱动依赖互不兼容的 Linux API 版本该怎么办？

Infiniband 驱动导入时曾尝试过集中垫片方案，但最终被放弃。一种建议是针对主流发行版固定一个流行的 Linux 版本，垫片就绑定它。除了 API 不稳定这一技术问题外，多数担忧集中在这样做对 FreeBSD 的利弊——尤其是对那些提供或不提供 FreeBSD 原生驱动的公司而言。

对于 DRM，我认为这样做是好事，甚至可能是必须的。XDC 期间我了解到一些事实，进一步印证了我的看法：

* AMD 雇佣数十名开发者开发其开源驱动。Intel 团队人数是其两倍。
* AMD 计划统一闭源 Catalyst 与开源驱动，产出开源“amdgpu”驱动，仅支持较新硬件。现有自由驱动仍会维护，以支持旧硬件。
* NVIDIA 希望改造其闭源驱动，让它注册为 DRM 驱动。它仍将是闭源驱动，用户需从 Ports 安装。
* Nouveau（NVIDIA GPU 的开源驱动）移植到 FreeBSD 应该不难，但耗时，因为我们的 TTM 内存管理器已经能工作。这能让我们开箱即用支持这些 GPU，尽管性能比不上专有驱动。此外这还能带来 GPGPU 支持，因为 NVIDIA 没有为 FreeBSD 提供 libOpenCL.so 库。
* ARM GPU 驱动目前主要是 GPL，但开发者愿意改为双许可证模式，与其他驱动一致。当初选 GPL 多半只是“默认”选择。

可以看出，让移植更省力会带来很多收益。我正在起草新方案，完成后将发布到 <freebsd-arch@FreeBSD.org> 邮件列表。

### DRM PRIME

解决 DRM 维护问题之后，下一个重要里程碑是 PRIME。DRM PRIME 是向用户态应用暴露的 API，允许在 GPU 之间迁移数据缓冲区。Linux 中基于其 dma-buf 内核设施实现。

什么时候需要这个特性？首先，用于支持配备两块 GPU 的计算机（多数是笔记本）：一块是低功耗 GPU 用于基本用途，另一块更强大，面向更高要求的任务。这种情况下，强大的 GPU 没有输出接口：它只是渲染引擎，第一块 GPU 拥有全部输出接口。借助 DRM PRIME，应用可以用第二块 GPU 渲染 3D 图像，把结果缓冲区交给第一块 GPU 显示到屏幕上。

另一种用途是虚拟化环境。虚拟机可以用物理 GPU 渲染图像，取回结果，在虚拟环境中使用。

### Mesa

Mesa 的问题较小，但数量众多。要更好评估这些问题的重要性，先要理解 Mesa 是什么。

### 瑞士军刀

Mesa 最初是 OpenGL 的开源实现。如今它是图形栈中最关键的用户态组件之一。它提供：

* OpenGL 和 OpenGL ES API，支持软件或硬件渲染；
* 硬件辅助的视频解码和编码；
* 用于 GPGPU 的 OpenCL 实现。

Mesa 已成为许多现代桌面环境的必备组件。例如合成器——那些在屏幕外渲染并组合应用窗口、再显示最终图像的窗口管理器——就依赖 Mesa。如果硬件渲染不可用，Mesa 提供基于 LLVM 的软件渲染器，性能足以胜任。

另一个例子是 Glamor：它在 OpenGL 之上提供 2D 加速。许多 GPU 已有原生硬件 2D 加速，多年来也发展出多种 API，如 XAA、EXA、UXA 或 SNA（UXA 和 SNA 专用于 Intel GPU）。这些方法能取得很好的 2D 性能，但维护成本巨大。如今 3D 引擎性能强劲，X 开发者决定也用它们做 2D 加速——当原生方法维护成本过高时，就交给 Glamor。Intel 在 SNA 上投入大量资金，会继续使用其原生方案。AMD 则在最新 GPU 上改用 Glamor 作为 2D 引擎。

其他厂商同理——投入 GPU 的人力有限——可以专注于 3D 驱动，几乎免费得到 2D 驱动。

对于 HTPC 或移动设备等低功耗平台，硬件辅助视频解码非常有用。Mesa 支持该特性，通过 NVIDIA 推出的 VDPAU API 暴露。Intel 风味的 VAAPI 未来也可能加入。

桌面环境之外，Mesa 还包含 Clover——OpenCL 的自由实现。不过这是仍在进行的工作，Mesa 中默认禁用 Clover。尽管如此，它对 FreeBSD 很重要，因为厂商目前不提供 OpenCL 库。

### Gallium

为了提供这些工具和 API，Mesa 内部有一套名为 Gallium 的基础设施。

Gallium 是暴露 GPU 功能的低级抽象层。在这层之上，每个高级 API（OpenGL、OpenCL、VDPAU、DirectX 等）的 Gallium state-tracker 把传入调用转换为 Gallium 调用。好处是只需为 GPU 开发一次 Gallium 驱动，就能通过所有高级 API 使用。

### udev

除内核驱动外，Mesa 对用户态需求很少。唯一必需的 Linux 专有库是 libudev。该库提供列举可用设备、获取或设置设备属性、监听事件等功能。其实现主要基于 **/sys** 伪文件系统。

FreeBSD 上，信息可从 sysctl 获取。Mesa（尤其是 Gallium）查询的数据有：

* 厂商和设备 PCI ID；
* 设备在 **/dev** 中的路径；
* 内核驱动名。

打开设备的文件描述符会传给 udev 以获取这些信息。然而 FreeBSD 缺少这个文件描述符与上述信息之间的关联。

目前我们实现了一个名为 libdevq 的小型库，满足 Mesa 特定需求，但我们希望它更通用。比如要获取驱动名和 PCI ID，需要查询 `hw.dri.0.name`，这是 DRM 特有的。因此需要扩展内核 API，记录设备驱动实例与其在 **/dev** 中条目和 sysctl 树（可能是 `dev.*` 树）之间的关联。

我们也可以扩展 libdevq 暴露 udev API，这有助于移植 Mesa 和 libinput 等其他库。

### Piglit

Mesa 开发者发布了名为 Piglit 的全面测试套件。这是评估 Mesa 新版本或内核驱动更新的绝佳工具。但我们并不定期运行它，需要让 Piglit 在 FreeBSD 上更容易运行。

所有依赖都已提交到 Ports 树。我认为缺少一个用于安装 Piglit 依赖的 meta-port。用户需要安装该 Port，然后检出并构建 Piglit。或许直接把 Piglit 做成 Port 对最终用户更友好，但维护这种 Port 需要频繁更新。Piglit 尚未发布，源码仓库每天都有新提交（改进的测试和新测试）。我们每次处理 Mesa 或内核时都需要使用它。等我们用熟了，就该把它加入报告 bug 或响应“召集测试者”时需要运行的清单。

### 与上游开发者合作

Mesa 仍需一些补丁才能在 FreeBSD 上构建，还需要若干补丁表明 FreeBSD 支持 Linux 同等特性。我们已尝试将它们发送上游集成到 Mesa。不幸的是，它们淹没在邮件列表中，因为邮件和补丁太多，我们未能引起注意。

我们需要更好地与上游开发者沟通，在合适时集成 FreeBSD 补丁。多亏 XDC，我们得以面对面交流，谈论此事后他们会更关注我们。等我们熟悉了他们的工作流程，他们甚至愿意授予我们提交权限——如果我们请求的话。

### FreeBSD 图形团队

要了解这些项目的进展或联系我们，请访问我们的 wiki 门户或全新的博客！

***

**Jean-Sébastien Pédron** 自 2013 年 1 月起参与 FreeBSD 图形栈开发。他之所以对这个领域产生兴趣，是因为他笔记本上的 Radeon HD 5870 几乎无人支持。如今他把大量业余时间花在图形团队里，改进 FreeBSD 上的图形栈并为之鼓与呼。不写 FreeBSD 的时候，他打鼓、敲打击乐，还喜欢轮滑，尤其是参加勒芒 24 小时轮滑活动。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://freebsd-journal-cn.bsdcn.org/20141112-shi-pin-qu-dong-cheng-xu/video-drivers.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
