X 和 Wayland 的主要区别

最近在写一个 Wayland Compositor,虽然我以前大概知道这是什么,但是并不是很清楚它和 Xserver 有什么区别,虽然 fc 老师的这篇文章 写的相当不错,但我一点也不懂 X 所以看的迷迷糊糊。偶然读了 这篇文章 发现十分不错,但因为是英文文章读起来很累,打算把一些理解的内容记下来。顺便说一下,原文是带示例的,效果非常不错,建议有时间的人慢慢看一遍。

我相信很多人在搜索 Wayland 的时候都看过这两张著名的图片:

但我觉得可能看了也不明白,怎么把 Xserver 砍掉就提高性能了?为什么没有见到 window manager?为什么桌面环境需要去支持 Wayland?

Wikipedia 上还有一些奇奇怪怪的图片比如这种:

在加上所有介绍 Wayland 的文章都会扯上 DRM,EGL,GLES 之类的,如果不懂这些就完全绕进去了,比如我就看到过有人问 Wayland 用 OpenGL ES 那用 OpenGL 的游戏是不是就跑不了了之类的。

这一切都得从头说起。

X 协议设计于 1980 年代,那时候窗口界面刚刚起步,人们还没什么 3D 特效一类的想法,而且机能也不允许,放到今天任何一个有点桌面基础的人都能理解应该给每个窗口一个 buffer 然后把这些 buffer 里的 texture 贴出来的设计逻辑,但 那时候可没那么多内存让你给每个窗口一个 buffer。所以就如同各种常见的领域一样,有个小天才一拍脑子想,反正 最后显示到桌面上的都是一个屏幕大小,我们只要准备这么大一块内存就行了嘛!换句话说,每个窗口的 buffer 要去掉自己被覆盖住的内存,整体内存大小就是可控的,在内存里是直接没有被覆盖的部分的

不得不说这位的思路在当时还是很有意义的,加上窗口大小都是矩形的假设,计算实际显示区域并不难,于是 Xserver 就是这样设计的。它维护一个屏幕大小的 buffer 自己计算窗口的实际位置,发生了变化(比如一个窗口盖住另一个),就给变化的窗口发一个重绘信号,这个窗口再发出绘图申请,直接绘制到 Xserver 的 buffer 里。由于 Xserver 知道所有窗口的位置,它就可以重定向鼠标键盘输入过去。然后具体的窗口移动缩放交给 window manager,它再把改过的位置回报给 Xserver。

一切事情都变得很美好,直到某天一个人提出一个问题:我想要半透明的终端!

程序员是不屑于解决提出问题的人的,如果用现代程序员的思维,做一下 alpha 混合其实很简单,只要 Xserver 能读取上层窗口的颜色和下层窗口的颜色就行了,可是你还记得当年的小天才吗?Xserver 说不太好意思,对于 一个像素我内存里只有一层,就是最上面显示的那个窗口……并且积习难改,我们不能改这个 feature……你想上下混合?死宅不要整天做梦,这是老祖宗留下来的不能改啊。

如果你用过没开启 混成 Compositing 的 XFCE 和半透明的 XFCE-Terminal,你会发现它是可以透出窗口下面的壁纸的,先别着急喊我骗子,你在终端下面放一个别的窗口试试?神奇的现象发生了,终端显示的还是壁纸……

上有政策下有对策嘛,一些终端作者想到反正壁纸总是固定的,我读取壁纸图片,取出终端所在的位置,然后在我窗口做个 alpha 混合不就行了?但是人不能自己骗自己啊,这是个客户端的假透明,我们要学习 GNOME 开发者的思维:不够好就砍掉。(大雾

X 一看不行啊,那我们改一下协议吧,加一个叫 混成器 compositor 的东西,如果你写了这个东西,X 就不是直接更新他自己的内存 buffer 了,而是交给混成器。混成器可以获取一系列窗口的内容,让它们都画到不同的 buffer 里面(内存终于够大了啊!),再把它们处理了丢到屏幕上去。Xserver 只是要求 compositor 最后返回一整个屏幕(通常是,也可以小一点)然后给这个直接贴到最上面去(可以简单理解为混成器画好一整张就行了,别的都不管了)。

理论上来说,混成器想怎么放这些窗口就怎么放这些窗口,就算想把他们丢到屏幕外边都行,反正你最后返回一个图就行了,Xserver 也不管是不是涩图。

但是有个尴尬的事情,输出给你管了,输入你管不着啊!之前说了 Xserver 自己按照自己存的窗口位置分配输入,你把窗口挪走了,Xserver 可还是按照自己记录的窗口位置分配输入的,如果你想自己处理窗口位置分配输入,好嘛,Xserver 里面的代码你再复制到你混成器里一份吧!

所以实际上 compositor 里面怎么做的呢?我最后处理完的窗口,位置和 Xserver 记录的位置还得一样,然后 Xserver 给我那个返回整张屏幕的顶层窗口,我就不接收输入了,这样直接透过顶层点到下面,就和窗口位置对应了(什么乱七八糟的破玩意啊!)。如果你要做个动画呢?你做动画的时候,Xserver 那边记录的位置可不跟你变(要是变,按照 X 的设计你这数据得跑好几个来回),你的鼠标点击在这时候是不准的,传不到窗口里面。

这些 compositor 都是各个桌面环境做的,他们一般都集成到自己的 window manager 里了。

而且随着时间发展,越来越多的 Xserver 和 client 是跑在同一个机器上的,很多 client 想自己利用显卡处理图形,就有人在协议上打洞,Xserver 做的越来越少了,更多的事情 client 自己都做了。

你还想再往 X 协议上糊一层吗?别糊了兄弟,你这也太挫了!一开始 X 的设计是提供机制而非策略,Xserver 自己是符合了(然后除了 Xorg 其他实现都死了),和 Xserver 配合的可是被他绑的死死的比如 compositor,性能翻了几倍还得拉着这些历史垃圾跑,Xserver 终于活成了自己最讨厌的样子。

Wayland 做的事情很简单,反正 compositor 都做这么多了,那直接把 Xserver 的功能也丢给 compositor 吧!Compositor 下层接的是 DRM 控制渲染,libinput 控制输入,GBM/EGLStreams 控制内存管理,上层更简单了,每个窗口丢给我一个 texture,我负责安排你们这些 texture 放在哪里,然后我按照我安排的位置,告诉你们鼠标进谁窗口了键盘进谁窗口了。然后因为要把这些 texture 混合到屏幕上,一般都用 OpenGL 的硬件加速,但在 Linux 下创建 OpenGL Context 的 GLX 库是和 X 绑定的,所以一般大家都用 OpenGL ES Context 的库 EGL。这个库只干扰最后合成图片时候的事情,至于你的 texture 用的是 OpenGL 还是 OpenGL ES 还是 CPU 画的都没有关系,现在 Wayland 一概不管了,你自己客户端处理自己的内容吧,我又不是 Xserver!

所以对于 GNOME 和 KDE 等等而言,现在他们打交道的一个是内核一个是窗口,而不是以前一样和 Xserver 打交道了,省了数据交换,同时自己可以自由控制窗口输入输出面积。Xorg 应该被淘汰不是因为功能性原因,而是因为它的设计在当时很聪明,但现在只是历史包袱,实在太挫了。

看完这篇文章建议回去阅读开头的两个链接,可以了解更多的实现细节,现在再看就不会那么混乱了。

Alynx Zhou

A Coder & Dreamer

既然看了喵写的文章,不打算投喂一下再走吗?哼!