3. Wayland架构解析
Wayland 并不是一个“新的图形服务器”,而是一套显示服务器协议加上其参考实现。理解 Wayland 的关键,是把它看成“客户端与合成器之间的一份通信契约”:客户端不再直接操作显卡和输入设备,而是通过协议请求合成器代为完成窗口合成、输入分发与缓冲区上屏。本节围绕协议、合成器、客户端-服务器模型、与 X11 的根本区别,以及 Surface、Seat、Output、Buffer 四个核心概念展开。
一、核心原理:协议 + 合成器 + 客户端-服务器模型
Wayland 架构由三部分组成:Wayland 协议定义对象、请求(request)和事件(event);合成器(Compositor)是服务器端,负责管理输出、输入、窗口与缓冲区合成;客户端是应用程序,通过 Unix 域套接字连接合成器,创建 Surface、提交 Buffer、接收输入事件。
与 X11 的“客户端-服务器 + 窗口管理器”分层不同,Wayland 把窗口管理、合成、输入分发统一收进合成器。合成器既是显示服务器,也是窗口管理器,还是合成引擎。这种“三合一”设计减少了中间层,使每一帧的路径更短,但也意味着合成器承担了更多职责。
二、Wayland 协议与通信模型
Wayland 协议基于对象模型:客户端连接后获得 wl_display 对象,通过它获取 wl_registry,再绑定 wl_compositor、wl_shm、wl_seat、wl_output 等全局对象。每个对象都有接口、请求和事件。客户端发送请求,合成器回送事件,形成双向异步通信。
# 查看当前 Wayland 会话信息
echo $XDG_SESSION_TYPE # wayland
echo $WAYLAND_DISPLAY # wayland-0
ls -l $XDG_RUNTIME_DIR/wayland-0
# 查看合成器暴露的全局对象(需安装 wayland-utils)
wayland-info | head -40
协议本身不规定合成策略,只规定“怎么问、怎么答”。因此 Weston、Mutter、KWin、Sway、Hyprland 等合成器可以有不同的窗口管理行为,但都遵循同一套协议。这也是 Wayland 生态“协议统一、实现多样”的根源。
三、与 X11 的根本区别
X11 的架构中,X Server 负责显示和输入,窗口管理器(如 Mutter、KWin)作为独立客户端运行,合成器(Compositor)又是另一个可选组件。Wayland 把这三者合并,带来几个根本差异:
- 渲染路径:X11 客户端通过 X 协议绘制到 X Server;Wayland 客户端直接渲染到 Buffer,再交给合成器合成。
- 输入处理:X11 由 X Server 分发到窗口;Wayland 由合成器根据焦点和 Surface 层级分发。
- 窗口管理:X11 依赖外部 WM;Wayland 由合成器内置窗口管理逻辑。
- 安全模型:X11 客户端可截屏、注入输入;Wayland 默认隔离,需通过 portal 授权。
- 同步机制:X11 依赖 XSync 等机制;Wayland 使用 frame callback 与 buffer release 事件。
| 对比维度 | X11 | Wayland |
|---|---|---|
| 服务器角色 | X Server 负责显示与输入 | 合成器负责显示、输入与合成 |
| 窗口管理 | 独立 WM 客户端 | 合成器内置 |
| 渲染方式 | X 协议绘制命令 | 客户端渲染 Buffer 提交 |
| 输入分发 | X Server 按窗口分发 | 合成器按焦点与 Surface 分发 |
| 安全隔离 | 弱,客户端可全局访问 | 强,默认隔离,需 portal |
| 同步机制 | XSync / 事件队列 | frame callback / buffer release |
四、核心概念:Surface、Seat、Output、Buffer
这四个概念是理解 Wayland 的“最小词汇表”:
- Surface:一块可绘制的矩形区域,是窗口、子窗口、光标、弹窗的抽象。客户端在 Surface 上提交 Buffer,合成器决定它显示在屏幕的哪个位置。
- Seat:一组输入设备的集合,代表“用户输入能力”。一个 Seat 可包含键盘、指针、触摸。客户端通过
wl_seat获取输入事件。 - Output:一个显示输出,如 HDMI 显示器、笔记本内屏。客户端通过
wl_output获知分辨率、刷新率、缩放比例和物理尺寸。 - Buffer:客户端渲染好的像素数据,通常通过
wl_shm(共享内存)或 DMA-BUF 提交。合成器读取 Buffer 并合成到最终画面。
五、案例场景:一个窗口从创建到上屏
假设一个 Wayland 客户端要显示一个 800×600 的窗口,典型流程如下:
- 连接
wl_display,获取wl_registry,绑定wl_compositor、wl_shm、wl_seat、wl_output。 - 通过
wl_compositor.create_surface()创建 Surface。 - 通过
wl_shm.create_pool()创建共享内存池,分配 Buffer。 - 将 Buffer 附加到 Surface,调用
commit()提交。 - 合成器收到提交,进行合成,并在下一帧通过 frame callback 通知客户端。
- 客户端收到 frame callback 后,渲染下一帧,再次提交 Buffer。
- Seat 将键盘、鼠标事件发送给客户端,客户端更新界面并重新提交。
这个流程中,客户端不直接访问显卡,也不直接读取输入设备,所有交互都通过协议完成。合成器负责决定窗口位置、层级、缩放和最终合成。
六、误区与复盘
另一个误区是“Wayland 不需要窗口管理器”。实际上窗口管理逻辑被内置到合成器中,只是不再以独立进程存在。还有开发者认为“Wayland 不能截屏”,实际上通过 xdg-desktop-portal 和 PipeWire,Wayland 可以实现安全的屏幕共享与截屏。
复盘来看,Wayland 架构的核心变化是职责合并与安全隔离:合成器统一管理显示、输入与合成,客户端只负责渲染自己的 Buffer。理解 Surface、Seat、Output、Buffer 四个概念,就能读懂大多数 Wayland 客户端与合成器的交互代码。