3. Wayland核心概念

Wayland 并不是一个“把 X11 换掉”的简单替代品,而是一套围绕合成器中心化重新设计的图形协议。理解 Wayland,关键是先厘清它把哪些职责交给了谁:谁负责画、谁负责合成、谁负责把输入事件送到正确的窗口。本节围绕显示服务器、合成器、客户端、表面、区域、缓冲区、输入设备与全局对象这八个核心概念展开,它们共同构成 Wayland 图形栈的“最小认知模型”。

一句话总览:客户端把内容画进缓冲区,缓冲区绑定到表面,表面按区域裁剪与提交;合成器作为显示服务器,把多个表面合成为最终画面,并把输入设备事件路由回对应客户端;全局对象则是客户端发现和绑定这些能力的入口。

Wayland 核心对象与数据流关系 客户端 Client wl_surface 表面 窗口/图层的内容载体 wl_region 区域 输入/裁剪的有效范围 wl_buffer 缓冲区 像素数据的共享内存/DMA-BUF wl_callback 帧回调 驱动下一帧绘制节奏 合成器 Compositor(显示服务器) 场景图 / 表面管理 维护表面层级、位置与可见性 渲染与合成 GPU/CPU 合成,输出到 DRM/KMS 输入事件路由 按焦点/区域分发键盘、指针、触摸 全局对象注册表 wl_registry 暴露可用接口 输入设备 wl_keyboard 键盘 wl_pointer 指针 wl_touch 触摸 全局对象 wl_compositor wl_shm wl_seat attach/commit set_input_region buffer 提交 事件 焦点 bind seat 提供 最终画面输出到显示设备(DRM/KMS)

一、显示服务器与合成器:Wayland 的“中心角色”

在 X11 中,X Server 负责窗口管理、输入分发和绘制协调,合成器是可选的额外组件。Wayland 则把显示服务器与合成器合并为同一个进程:合成器就是显示服务器。它同时承担协议服务端、场景图管理者、渲染合成者和输入路由者四种角色。常见的 Weston、Mutter、KWin、Sway、Hyprland 都是合成器实现,它们各自决定窗口如何排列、动画如何播放、输入如何分发。

这种设计带来的直接变化是:客户端不再直接操作屏幕,也不能随意读取其他窗口内容。客户端只能通过协议向合成器“提交”自己的表面内容,由合成器决定最终显示结果。这既提升了安全性和一致性,也让合成器成为性能与体验的关键瓶颈。

二、客户端、表面、区域与缓冲区:内容如何被表达

客户端是任何使用 Wayland 协议绘制界面的进程,例如终端、浏览器、视频播放器。客户端与合成器之间通过 Unix Domain Socket 建立连接,随后使用 wl_surface 表达“我要显示一块内容”。表面本身不包含像素,它只是一个抽象容器,必须绑定缓冲区才有实际内容。

wl_buffer 是像素数据的载体,常见来源包括 wl_shm 共享内存缓冲区和基于 DMA-BUF 的 GPU 缓冲区。客户端绘制完成后,通过 attach 把缓冲区挂到表面,再调用 commit 提交。合成器收到提交后才会把该表面纳入下一帧合成。

wl_region 用于描述表面上的有效区域,最典型的用途是设置输入区域:只有落在该区域内的指针事件才会被路由给这个表面。区域还可以用于裁剪和损伤区域(damage region)优化,减少不必要的重绘。

/* 客户端提交一帧的典型顺序(伪代码) */
surface = wl_compositor_create_surface(compositor);
buffer  = create_shm_buffer(width, height, stride, format);
draw_into(buffer);

wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage_buffer(surface, 0, 0, width, height);
wl_surface_set_input_region(surface, input_region);
wl_surface_commit(surface);   /* 此刻合成器才看到新内容 */

三、输入设备与全局对象:能力如何被发现和绑定

输入设备在 Wayland 中通过 wl_seat 抽象。一个 seat 代表一组输入能力,通常包含键盘、指针和触摸。客户端不能直接打开 /dev/input/event*,而是从 seat 获取 wl_keyboard、wl_pointer、wl_touch 对象,并接收合成器路由过来的事件。键盘焦点由合成器决定,只有获得焦点的表面才会收到按键事件。

全局对象是客户端发现服务端能力的机制。客户端连接后首先绑定 wl_registry,通过监听 global 事件获知合成器暴露了哪些接口,例如 wl_compositor、wl_shm、wl_seat、xdg_wm_base、wl_output 等。客户端根据自身需要选择绑定,未绑定的全局对象不会产生任何开销。

核心对象 角色 典型接口 关键行为
显示服务器/合成器 协议服务端 + 渲染合成 wl_display、wl_compositor 管理场景图、合成输出、路由输入
客户端 内容生产者 wl_surface、wl_buffer 绘制、提交、响应帧回调
表面 内容容器 wl_surface attach/commit/damage
区域 范围描述 wl_region 输入区域、裁剪区域
缓冲区 像素载体 wl_buffer、wl_shm 共享内存或 DMA-BUF 像素数据
输入设备 事件来源 wl_seat、wl_keyboard、wl_pointer 焦点管理、事件分发
全局对象 能力注册表 wl_registry 发现并绑定服务端接口

四、案例与场景:一个窗口从创建到显示

假设一个终端客户端启动,它首先连接 wl_display,获取 wl_registry,绑定 wl_compositor、wl_shm、wl_seat 和 xdg_wm_base。随后创建 xdg_surface 和 wl_surface,申请共享内存缓冲区并绘制文字。提交后,合成器把该表面加入场景图,并在下一帧合成到屏幕。

当用户点击窗口时,合成器根据表面位置和输入区域判断命中,把 wl_pointer 事件发送给该客户端;当用户按键时,合成器把键盘焦点切到该表面,客户端收到 wl_keyboard.key 事件。整个过程客户端从未直接接触显示设备,也未读取其他窗口内容。

调试提示:使用 WAYLAND_DEBUG=1 运行客户端,可以打印完整的协议消息流,观察 wl_surface@N.commit、wl_buffer@N、wl_pointer@N.motion 等事件顺序,是理解对象关系最快的方式。

五、常见误区与复盘

  • 误区一:把 Wayland 当成“另一个 X Server”。Wayland 是协议,合成器才是服务端实现;没有合成器就没有 Wayland 会话。
  • 误区二:认为表面等于窗口。表面只是内容容器,窗口语义由 xdg_wm_base 等扩展协议定义。
  • 误区三:客户端可以直接读输入设备。输入事件必须经合成器路由,客户端只能通过 seat 获取。
  • 误区四:全局对象越多越好。全局对象是能力声明,客户端应按需绑定,避免无谓的协议往返。

复盘要点:排查 Wayland 显示问题时,先确认合成器是否正常运行,再确认客户端是否成功绑定 wl_compositor 与 xdg_wm_base,最后检查缓冲区格式与提交时序。多数“黑屏”问题源于缓冲区未提交或格式不被合成器支持,而非协议本身。

掌握这八个概念后,再看任何 Wayland 客户端或合成器代码,都能快速定位“谁在画、谁在合成、谁在分发输入、能力从哪里来”。这是后续学习协议扩展、输入法、屏幕共享与性能优化的共同基础。