Linux 显示软件栈贼复杂,是我见过最复杂的系统,然后我本来就挺笨的。关于 Linux 显示软件与技术栈,说错我不负责,你看看就好。
说一下 2D 渲染#
科普一下 X Server 相关的库#
Xlib、XCB、GTK、Qt、X Toolkit 的关系:
Xlib 是一个用于 2D 绘图的 C 函数库,用来与 X Server 通信。有了 Xlib,开发者就可以在不了解 X Protocol 细节的情况下编写图形界面。Xlib 现在逐渐被 XCB 取代:Xlib 是 1985 年的项目,XCB 是 2007 年的项目,XCB 重新实现了 Xlib 的核心能力。
Xlib 仍然属于底层库,不提供 Button、Widget、Dialog 这样的组件,那不得搞死人。所以程序员一般不会直接使用 Xlib,而是使用更高层次的图形库,比如 X Toolkit、GTK、Qt、SDL 等。但注意,调用 Xlib 不是这些图形库唯一的绘图办法,许多图形库也可以直接和图形硬件通信。
这里放一张图:

如果你有编写 X Toolkit(Xt)及上层库如 Motif 的开发经验,那么叔叔你好,你的孩子可能都比我大了。
X Server 的角色和内部的 DDX 驱动#
简单说一下:Xlib 是通过 X Server 间接完成所有绘图。Xlib 通过 X11 Protocol 发送渲染指令,X Server 接收并处理这些指令,再将其转换为硬件绘图的实际指令。也就是说,X Server 能将 X Protocol 这种与硬件无关的指令转换为与图形设备相关的硬件指令。
X Server:虽然我不是显示驱动,但我也干显示驱动的活,蛤蛤蛤。
可是显示硬件很多,ARM Mali GPU 就有一堆不同的型号,再加上 Intel、AMD、NVIDIA,X Server 需要把统一的 X Protocol 转化为每个厂商、每种硬件专有的绘图语言,这就涉及巨量 GPU 寄存器和显示内存的读写操作。X Server 的代码岂不是日渐肥胖到最后无法维护。
所以 X Server 内与特定显示硬件相关的代码就需要独立出来,成为单独的用户空间二进制库,这就是 X Server 内的 DDX 用户空间驱动。DDX 用户空间驱动才是真正的显示驱动,但 DDX 驱动也只是整个显示驱动的一部分。

如果你用的 Ubuntu,Intel 集成显卡,那么你会发现系统中有这个软件包: xserver-xorg-video-intel,这就是 Xserver 内的 DDX 驱动。
3D 绘图的情况#
OpenGL 不是库函数,是一个 3D 绘图标准#
虽然 OpenGL 的全称是 Open Graphics Library,但它不是某个具体的二进制库,而是一个标准。OpenGL 定义了差不多 350 多个标准 2D/3D 绘图指令,其指令就像这样:

这里是 OpenGL 3.1 规范里 Shader 相关的函数:

OpenGL 因为它是无形的,所以不仅跨语言,还跨平台。显示硬件厂商大多会根据 OpenGL 规范实现一套闭源的 GL 函数库,也就是 libGL.so,并且厂商给出的 libGL.so 一般都带有硬件加速功能。
逼逼赖赖几句:显示硬件属于计算机硬件中黑盒子中的黑盒子,所以 OpenGL 的具体实现大多由厂商编写,部分有机会开源,某些 ARM 平台提供的 libGL.so 驱动不仅闭源还非常不友好。理想情况下,厂商应该根据 OpenGL 标准去实现 libGL.so 图形库,但很多厂商还是个大爷:我可以不按 OpenGL 的标准去实现 libGL.so,我也可以魔改扩展 OpenGL,导致 OpenGL 从规范变成了参考,干脆叫 libFuckYourselfGL.so 算了,蛤蛤蛤。
X Server 通过 GLX 转发 GL 指令,实现 3D 绘图的间接渲染#
厂商给出的 libGL.so 能直接操作显示硬件的寄存器和显存。一些独占屏幕的 3D 应用可以直接调用厂商给的 libGL.so 进行带硬件加速的 3D/2D 绘图。我初中的电子词典 UI 就是 Qt 桌面,独占显示,使用的是闭源的 MIPS 处理器,北京君正生产的 Jz4740 SoC,使用不知道从哪里来的闭源 libGL.so 进行绘图,打 NES 游戏能到 30fps,效率还可以。
但这明显不兼容 Linux 已有的显示栈,因为早期的 Linux 上只有 X Server,开发者也不想大改 Linux 的显示软件栈。所以开发者搞了一组扩展叫 GLX(OpenGL Extension to the X Window System)。
GLX 是一组对 X Window System 的扩展,主要由三部分组成:
- OpenGL 函数的编程接口,好让 X Window System 之上的程序可以使用 OpenGL 指令
- 扩展 Window Protocol,让运行在 X Server 之上的程序可以发送 OpenGL 指令给 X Server
- 扩展 X Server,使 X Server 能处理和接收 GL 渲染指令,并将它们传递给厂商提供的
libGL.so库,当然也可以是其它libGL.so,比如完全开源的 Utah GLX driver。
然后整个架构得就像这张图:

这种渲染方式叫 间接渲染(indirect rendering),使用 OpenGL 指令每次都需要经过 X Server。显然这种渲染方式效率比较低,因为中间多了一层 X Server 对 GL 指令的转发,在密集绘图和渲染时,每次这么一来一回显然是资源浪费。
直接渲染#
再写就猝死了…..我先去睡一下。

