tech-sharing / 2026-05-09

Wayland
基础概念与优势

从 X11 到 Wayland:为什么显示服务器值得一次重新设计。

@paxseekertech sharing · 30 min

agenda.toml

今天的路线图

01背景:X11 做对了什么,做错了什么~5min
02Wayland 核心概念:协议、合成器、客户端~8min
03协议层:wl_protocol / wl_surface / wl_buffer~5min
04优势解读:流畅渲染、低延迟、安全隔离~7min
05生态现状:谁在用、还差什么~3min
06Takeaways + Q&A~2min

// x11-legacy

X11 做对了,
但已经不再够用。

网络是设计的核心

X11 诞生于 1984 年,网络透明是灵魂——所有渲染都经过 socket。Overhead 极高。

❌ 本地渲染也走网络协议

扩展膨胀

30 年生态积累了几百个 extension,GE、GLX、DRI……相互叠加,维护成本爆炸。

😩 扩展地狱

安全模型弱

任何 X 客户端理论上可以监听/控制其他窗口。等同于 root 权限级别的攻击面。

❌ 缺乏沙箱

// wayland-core

Wayland 的设计哲学:
极简、可组合、安全。

Wayland 不是协议的全部——它只是一个架子。实际协议是 wl_protocol,通过 wayland-scanner.xml 生成。

✓ 无网络透明(本地优先)
✓ 客户端直接渲染,合成器只合成
✓ 无继承性权限提升
✓ 可选的 Mesa EGLDirect

三个角色

1. Client — 应用本身
2. Compositor — 合成器(也是服务端)
3. DRM/KMS — 内核 DRM 子系统
Client 与 Compositor 通过
Wayland 协议通信(Unix Socket)

// globals

全局对象:
每个 Wayland 连接的灵魂。

Client 与 Compositor 通过 wl_display 建立连接。全局对象由 wl_registry 统一注册和发现。

wl_display — 连接句柄
wl_registry — 全局对象目录
wl_compositor — 创建 surface
wl_shm — 共享内存池
wl_output — 输出设备(显示器)
wl_seat — 输入设备聚合(键盘/鼠标)
wl_registry.bind
// 绑定一个全局对象
let comp = wl_compositor.bind(
    registry, name, version, id
)
// name → Compositor 全局对象的 id
// version → 协商接口版本

// 全局对象列表由 Compositor 发布,
// Client 通过 wl_registry.listener 接收。

// event-queue

事件循环:
wl_display 的 dispatch 模型。

Wayland 连接基于 wl_event_queue。Client 调用 wl_display.dispatch() 读取 socket 并分发消息。没有独立线程模型——默认在调用线程处理。

wl_display.prepare_read() — 准备读
wl_display.read_events() — 阻塞读
wl_display.dispatch_pending() — 分发队列消息
wl_display.flush() — 发送 Client 请求

典型主循环

while (running) {
wl_display.prepare_read()
if (can_read) {
wl_display.read_events()
wl_display.dispatch_pending()
}
wl_display.flush()
wait_for_fd(...) // epoll
}

// wl-protocol.xml

wl_surface + wl_buffer:
渲染的最小单元。

Client 创建 wl_surface,填充内容写入 wl_buffer(由合成器分配或 Client 自己提供),然后 commit 给 Compositor 合成。

wl_compositor.create_surface()
wl_shm_pool(共享内存)
wl_buffer.attach → commit
protocol.wire
// Client → Compositor (Unix FD)
wl_bufferattach(surface, buffer, x, y)
wl_surfacecommit()

// Compositor → Client
wl_bufferrelease()
wl_callbackdone(callback_data)

// image-data-flow

图片数据:从文件到显示的完整流程。

一张图片的完整渲染链路,涉及多个全局对象的协作。

1. wl_shm / wl_dmabuf — 分配 buffer
2. 写入 pixel 数据到 shm pool
3. wl_compositor.create_surface()
4. wl_buffer.attach → surface.commit()
5. Compositor 接收 commit,读取 buffer
6. Compositor 合成到屏幕
7. wl_buffer.release() 通知 client

全局对象调用链

wl_display → connect()
wl_registry → bind(wl_shm)
wl_shm → create_pool(size)
wl_shm_pool → create_buffer()
wl_compositor → create_surface()
wl_surface → attach(buffer,0,0)
wl_surface → commit()

// advantages

Wayland 的三个核心优势。

1 · 零拷贝渲染

Client 直接写入 shared memory 或 DMA buffer,Compositor 直接从 GPU 读取,无需 X11 的 CPU 中转。延迟从 ~16ms 降到 ~1ms。

⚡ 低延迟

2 · 主动式合成

X11 是被动合成(应用通知才更新)。Wayland Compositor 可以在任何时候重绘。滚动撕裂?不存在的。

🎯 无撕裂

3 · 真正的沙箱

Client 只能操作自己的 surface,没有 keystrokes、screenshots 权限(除非明确 granted)。flatpak / portals 的基础。

🔒 安全隔离

// ecosystem

生态现状:主流桌面已就绪。

GNOME / KDE 均已默认 Wayland 多年。游戏和媒体是最后两个痛点。

✓ GNOME 45+ 默认 Wayland
✓ KDE Plasma 6 默认 Wayland
✓ Steam (Proton) 支持
~ 部分 Electron 应用仍需 XWayland

XWayland 兼容层

遗留 X11 应用通过 XWayland 运行(合成器内置 X 服务器)。Wine / Steam / Electron 都走这条路。

⚠️ XWayland 下性能与纯 X11 持平

// takeaways

三件事带回去。

1 · Wayland 不只是一个协议

它是一套设计哲学——本地优先、最小接口、合成器中心。

2 · 全局对象是发现机制

wl_registry 是所有功能的入口,通过 bind 获取具体接口。版本协商决定兼容性。

3 · 事件循环是同步模型

wl_display.dispatch() 在调用线程分发消息。多线程使用需创建独立 wl_event_queue。

延伸阅读:wayland-book.freedesktop.org · wayland.freedesktop.org/docs