2. Linux 图形栈全景:从应用程序到显示硬件的完整数据流
在深入 Weston 合成器与 KMS 框架配置之前,必须先建立 Linux 图形栈的整体视图。本章将剖析一条完整的显示数据流:从应用程序调用图形 API 开始,经过合成器调度、内存管理,最终通过 KMS 驱动将像素输出到物理显示器。理解这一全景是后续配置与调试的基础。
2.1 图形栈层次结构总览
Linux 图形栈自底向上可分为四层:硬件层、内核层、合成器/窗口管理层、应用层。每一层都承担特定的职责,并通过标准接口与相邻层通信。
核心要点:DRM/KMS 是内核空间的标准显示框架;GEM 负责显存管理;Wayland 是应用与合成器之间的通信协议;Weston 是 Wayland 协议的参考合成器实现。这四个组件构成了现代嵌入式 Linux 显示系统的软件支柱。
2.2 核心组件层次关系
在图形栈中,DRM/KMS、GEM、Wayland 和 Weston 四个组件分别处于不同层级,它们之间的协作关系决定了显示系统的整体行为。
| 组件 | 全称 | 层级 | 核心职责 |
|---|---|---|---|
| DRM | Direct Rendering Manager | 内核层 | 提供 GPU 和显示控制器的统一访问接口,管理显示资源(CRTC、Encoder、Connector、Plane) |
| KMS | Kernel Mode Setting | 内核层(DRM 子模块) | 负责显示模式设置(分辨率、刷新率、像素时钟)、帧缓冲管理和页面翻转 |
| GEM | Graphics Execution Manager | 内核层(DRM 子模块) | 管理显存分配、释放、共享和同步,支持 DMA-BUF 跨设备共享 |
| Wayland | Wayland Protocol | 协议层(应用与合成器之间) | 定义应用(Client)与合成器(Compositor)之间的通信协议,取代 X11 |
| Weston | Weston Compositor | 合成器层 | Wayland 协议的参考实现,负责窗口管理、合成渲染、输入事件分发 |
层次关系速记:Weston 通过 Wayland 协议接收应用的图形缓冲区,然后调用 DRM/KMS 接口将这些缓冲区合成并输出到显示器。GEM 负责管理这些缓冲区在显存中的生命周期。简言之:应用 → Wayland → Weston → DRM/KMS/GEM → 硬件。
2.3 完整数据流:从应用像素到屏幕像素
一条完整的显示数据流包含以下关键步骤。理解每一步的参与者与数据载体,是调试显示问题的前提。
- 应用渲染:应用程序(如 Qt 或 GTK 应用)使用 OpenGL ES / Vulkan 或软件渲染,将内容绘制到 Wayland 共享缓冲区(wl_buffer)中。
- 缓冲区提交:应用通过 Wayland 协议将缓冲区句柄提交给 Weston 合成器,并附带窗口属性(位置、大小、透明度等)。
- 合成器接收:Weston 接收来自多个应用的缓冲区,使用 GPU 或 CPU 进行合成(Compositing),生成最终的帧缓冲区。
- GEM 管理:合成过程中,所有缓冲区都通过 GEM 分配在显存中,DMA-BUF 机制允许不同设备(如 GPU 与显示控制器)共享同一块物理内存。
- KMS 提交:Weston 将合成后的帧缓冲区通过 DRM/KMS 的
drmModeAtomicCommit或drmModePageFlip提交给内核。 - 硬件扫描输出:KMS 驱动配置 CRTC(显示控制器)从指定帧缓冲中读取像素数据,经过 Encoder 编码,通过 Connector 输出到物理显示器。
2.4 DRM/KMS 核心对象模型
DRM/KMS 在内核中维护了一套标准化的显示对象模型。Weston 通过操作这些对象来完成显示配置。理解这些对象是编写或调试 KMS 代码的基础。
| 对象 | 描述 | 关键属性 |
|---|---|---|
| CRTC | 显示控制器,负责从帧缓冲读取数据并生成视频时序 | 分辨率、刷新率、扫描模式、关联的 Plane |
| Encoder | 编码器,将 CRTC 输出的数字信号转换为特定接口标准(如 HDMI、LVDS、DSI) | 编码类型、支持的 Connector 列表、可能的 CRTC 掩码 |
| Connector | 物理连接器,代表显示器接口(HDMI 端口、eDP 接口、DSI 接口) | 连接状态(connected/disconnected)、EDID 数据、支持的显示模式列表 |
| Plane | 硬件图层(Overlay/Primary/Cursor),支持独立缩放和颜色转换 | 格式、位置、大小、关联的 Framebuffer、Alpha 值 |
| Framebuffer | 帧缓冲,内存中的像素数据容器,由 GEM 对象创建 | 宽度、高度、像素格式、GEM handle、DMA-BUF fd |
常见误区:初学者常将 CRTC 与 Connector 混淆。CRTC 是控制器,负责生成时序;Connector 是物理接口,负责连接显示器。一个 CRTC 可以驱动多个 Connector(克隆模式),但通常一个 Connector 只连接一个 CRTC。
2.5 GEM 与 DMA-BUF:显存管理核心机制
GEM 是 DRM 框架中的显存管理器,提供以下核心能力:
- 分配与释放:通过
drmIoctl(DRM_IOCTL_GEM_CREATE)分配显存,返回 GEM handle。 - 内存映射:通过
drmIoctl(DRM_IOCTL_GEM_MMAP)将显存映射到用户空间地址。 - 句柄与 FD 转换:GEM handle 是进程内的句柄,通过
drmIoctl(DRM_IOCTL_GEM_FLINK)转换为全局名称(name),或通过drmIoctl(DRM_IOCTL_PRIME_HANDLE_TO_FD)转换为 DMA-BUF 文件描述符。 - 跨进程/跨设备共享:DMA-BUF 是 Linux 内核的通用缓冲区共享机制,允许 GPU、显示控制器、VPU、ISP 等不同硬件模块共享同一块物理内存,避免数据拷贝。
// GEM 分配与 DMA-BUF 导出示例(伪代码)
int fd = open("/dev/dri/card0", O_RDWR);
// 1. 分配 GEM 对象
struct drm_gem_create gem_create = {
.size = width * height * 4, // RGBA8888
.handle = 0
};
drmIoctl(fd, DRM_IOCTL_GEM_CREATE, &gem_create);
// 2. 导出为 DMA-BUF FD
int dma_buf_fd;
struct drm_prime_handle prime_handle = {
.handle = gem_create.handle,
.flags = DRM_CLOEXEC,
.fd = 0
};
drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle);
dma_buf_fd = prime_handle.fd;
// 3. 将 DMA-BUF FD 传递给 Weston 或其他驱动
// 接收方可通过 prime_fd_to_handle 导入
2.6 Wayland 与 Weston 的协作模式
Wayland 协议定义了 Client(应用)与 Compositor(合成器)之间的通信规范。Weston 作为参考实现,遵循以下协作模式:
| 角色 | 职责 | 关键接口/对象 |
|---|---|---|
| Wayland Client | 创建 wl_surface,渲染内容到 wl_buffer,提交给 Compositor | wl_display、wl_surface、wl_buffer、wl_shell/xdg_shell |
| Wayland Compositor (Weston) | 接收所有 Client 的缓冲区,合成最终画面,通过 DRM/KMS 输出 | wl_compositor、wl_subcompositor、wl_output、weston_output |
| 共享机制 | Client 与 Compositor 通过共享内存(wl_shm)或 DMA-BUF(linux_dmabuf)传递缓冲区 | wl_shm、zwp_linux_dmabuf_v1 |
关键设计理念:Wayland 协议中,Compositor 是唯一可以直接访问 DRM/KMS 的实体。Client 不能直接操作显示硬件,只能通过 Wayland 协议将缓冲区交给 Compositor。这种设计保证了显示系统的安全性和稳定性,避免了 X11 中常见的窗口争用问题。