GUI_0">Linux中的GUI与图形栈
在本文中,我们将探讨基于Linux操作系统中使用的图形栈。我们将了解使图形应用程序成为可能的不同技术,以及它们是如何相互交互的。我们将从基础开始,逐步引导至高级的GUI工具包。
最后,我们将讨论这些技术是如何结合在一起,形成一个成熟的图形体验的。
1、Linux内核
“Linux”这个名字仅仅指的是Linux内核。它不是一个包含所有功能的完整操作系统,而是一个围绕其建立一切的内核。内核是实际硬件和进程之间的接口。
如果我们在一台机器上构建并安装一个Linux内核以及辅助工具和实用程序,我们可以通过虚拟终端中的内核模式设置获得非常原始的图形,但不能获得复杂的图形,如程序窗口、视觉效果以及带有精美渐变的图像。为了使Linux能够处理复杂图形,我们需要一个完整的图形栈,包括图形驱动程序、图形API包装器、窗口系统、合成器等。
因此,大多数基于Linux的操作系统,如Ubuntu、Debian和openSUSE,都将这些图形栈打包在它们的发行版中。因此,我们可以开箱即用访问图形环境。然而,如果我们使用其他操作系统,如Arch、LFS、Gentoo或Alpine,我们需要手动配置图形栈才能访问图形环境。
因此,总的来说,Linux本身没有内置的原生GUI或标准化的库,通过这些我们可以开发GUI程序。尽管如此,我们可以通过许多库、GUI工具包、驱动程序和包来拥有一个图形系统。
2、图形API
图形API负责将一般的指令集,如绘制三角形,转换为GPU可以执行的更具体的代码。因此,图形API描述了开发者代码如何与GPU接口。
有几个流行的图形API,如OpenGL、OpenGL ES、Metal、Direct3D和Vulkan。然而,Linux上的大多数图形栈大量使用OpenGL,因为它是免费的且跨平台。
2.1 OpenGL API
OpenGL代表开放图形库。它是一组规范,专门关注2D和3D图形的硬件加速渲染,而不考虑平台。该API的原生语言是C。然而,也有其他语言的绑定,比如Java、Golang和Rust。
准确地说,OpenGL并不是一个确切的库,因为每个供应商都必须实现这个规范来生成一个OpenGL库。因此,在基于Linux的发行版中,libGL.so库文件对于每个供应商都会有所不同。此外,OpenGL规范有多个实现,包括第三方和开源实现。
2.2 Mesa
Mesa是OpenGL API和Vulkan的开源实现。它使用特定于显卡的驱动程序将API转换为硬件特定的形式。此外,Mesa支持Gallium3D架构来构建3D图形驱动程序,这使得它可以移植到所有主要的操作系统。
现代显示服务器和窗口管理器,如X.Org和Wayland,内部使用OpenGL,因此所有的图形都通过Mesa进行处理。
2.3 GLES
GLES为OpenGL嵌入式系统。它是一种针对嵌入式设备(如Android手机和iPhone)的OpenGL配置文件。
2.4 GLX和WGL
正如我们上面看到的,OpenGL只关注于绘制2D和3D图形,它没有窗口管理的概念。因此,我们需要一种方法将OpenGL场景与窗口绑定。GLX是X Window系统的一个扩展,提供了OpenGL场景与X Window系统之间的接口。
类似于GLX,WGL是OpenGL与微软Windows原生窗口系统之间的接口。
2.5 EGL和GLUT
EGL是一个平台无关的API,提供了OpenGL与操作系统原生窗口系统之间的接口。它不依赖于GLX或WGL,而是让供应商实现其规范。
不同于EGL,GLUT是围绕GLX和WGL的一个包装器,使我们能够编写可移植的图形应用程序。
2.6 fglrx 和Catalyst
Catalyst是AMD的Xorg OpenGL驱动程序,之前被称为fglrx。它是X.Org的一个专有驱动程序,并拥有自己的OpenGL规范实现。
3、DRM和DRI
OpenGL和窗口系统各自实现了与屏幕上绘制对象相关的部分。因此,它们生成一组特定于显卡的指令,这些指令通过直接渲染管理器(DRM)由Linux内核处理。
在Linux上,我们有一个libdrm库,它使得访问操作系统上的DRM变得容易。DRM使用一组通用的系统ioctl调用为图形对象分配内存,并填充所需的命令和纹理。ioctl系统是一种特殊类型的系统调用,用于处理设备特定的输入和输出操作。在这种情况下,它处理视频卡的输入和输出操作。
因此,当我们运行一个图形应用程序时,它会加载OpenGL驱动程序——例如Mesa。然后,驱动程序加载libdrm,这使得可以直接通过ioctl与内核通信。
只要图形应用程序在运行,这个过程就会继续。然而,我们需要一种方式让窗口系统(如X服务器)知道发生了什么,以便它可以同步和更新自己。这种同步过程被称为直接渲染基础设施(DRI)。
3.1 KMS
当我们有一个运行中的X服务器或合成器时,图形应用程序工作得很好。那么,在X服务器外部运行的图形怎么办,比如虚拟终端和加载启动屏幕?这就是内核模式设置子系统发挥作用的地方。
KMS是Linux内核和libdrm中的一个子系统,它使我们能够通过ioctls直接配置实际硬件。因此,我们不必依赖于X服务器。然而,我们应该注意,KMS是一个非常低级的子系统,只有在无法运行图形服务器或合成器时才应该使用。
4、X窗口系统
X Window系统是一个开源的窗口系统,被大多数基于Linux的发行版使用。它基于客户端-服务器架构,提供了一种网络透明的与窗口交互的方式,这种方式也可以在远程环境中使用。
它不仅为GUI环境提供了基本框架,还负责事件处理和视觉装饰。
4.1 X11
由于X Window系统基于客户端-服务器架构,客户端和服务器可以不在同一台机器上。因此,我们需要一个协议来在客户端和服务器之间传递消息。X11协议负责消息的传递。当客户端和服务器在同一台机器上时,消息通过UNIX套接字交换。
此外,X11是可扩展的。因此,添加新功能而无需创建新协议或破坏现有客户端是很容易的。其中一个最有用的扩展是XRender,它增加了对反锯齿绘图的支持。
4.2 XLIB和XCB
X库,或称为Xlib,是客户端实现。这个库被图形工具包如GTK+和QT用来创建软件应用的图形前端。
XCB或X C语言绑定也是X的客户端实现。然而,它比Xlib层次更低,部分Xlib使用XCB来实现某些功能。
4.3 X.Org Server
X.Org是X Window系统的服务器端实现。它是Unix类系统上最常用的显示服务器。X.Org服务器通常由显示管理器启动,或者可以从虚拟终端手动启动。
5、Cairo
Cairo是一个专门处理矢量图形的绘图库。它实际上实现了与HTML5 canvas 相同的API。此外,它还通过Xlib后端支持绘制到X11表面。
虽然我们可以直接使用Cairo,但主要在像GTK+这样的绘图工具包中使用它。它还支持通过OpenGL进行渲染。
5.1 Pixman
X服务器和Cairo各自拥有自己的像素级操作实现,这导致了代码臃肿。为了解决这个问题,开发了Pixman。Pixman是X服务器和Cairo共享的库,提供了光栅化算法、渐变支持等更多功能。
6、合成器(Compositor)
合成器是一个程序,它为屏幕上的每个窗口提供一个离屏缓冲区。这个缓冲区也被称为复合覆盖窗口(Composite Overlay Window,COW),由合成器进行操作。因此,合成器可以应用额外的样式,如阴影、透明度和渐变。不仅如此,它还可以提供垂直同步和无撕裂的体验。
每个运行中的窗口的每一帧都会通过合成器。合成器从X服务器抓取窗口的光栅图,并将其渲染到OpenGL场景中。
7、Wayland
虽然X仍然功能齐全且稳定,但它存在相当多的问题。首先,由于其网络透明性的设计,它本质上是不安全的,因此负载容易受到有害的嗅探攻击。其次,它是一个非常旧的窗口系统,严重依赖于扩展,部分功能已经被移植到Linux内核中。
Wayland是X的新替代方案。Wayland不依赖客户端-服务器架构。因此,它作为窗口管理器或合成器,通过evdev处理事件并使用我们讨论过的相同堆栈显示窗口。Wayland的协议也基于UNIX套接字。
Wayland客户端向合成器请求一个缓冲区,并使用OpenGL、Cairo或任何其他渲染模块在其中绘制。合成器可以轻松地在将缓冲区交给客户端之前对其进行视觉效果操作。因此,从某种意义上说,合成器既是服务器又是合成器。
7.1 XWayland
XWayland提供了一个在Wayland下运行的X服务器。因此,它是在向Wayland过渡期间为X应用程序提供兼容性的一个包。然而,由于消息通过Wayland合成器传递,它在X客户端和X服务器之间添加了额外的一层。
GUI_137">8、GUI工具
GUI工具包或GUI库包含创建图形界面和元素(如小部件、场景和事件处理程序)所需的功能。一些GUI工具包是提供小部件、图形设计器和开发环境的全功能框架。
GUI工具包库通常是低层库(如Xlib或XCB)的包装器。因此,它为我们提供了一种更简单的方法来开发具有额外样式和行为的图形应用程序。
此外,大多数成熟的GUI工具包都有自己独特的设计理念。换句话说,它们实现了自己的标记语言、事件系统和状态机。状态机负责管理本质上反应复杂的程序。
有各种各样的GUI工具包,各有其用途。今天最常用的包括GTK+、Qt、wxWidgets、FLTK和imgui。我们来仔细看看其中的几个。
8.1 GTK+
GTK+ 或 GIMP 工具包是 Unix 类操作系统的首选工具包,这些系统使用 X 窗口系统和 Wayland。它是一个稳定的 GUI 工具包,用于构建跨平台和现代的 GUI 应用程序。一些最受欢迎的 GUI 程序是用 GTK 开发的,包括 GIMP、Mozilla Firefox、GNOME 桌面环境、Inkscape 和 Pidgin。
GTK 工具包也有其他后端的子系统,例如 Windows 的 GDI 和 macOS 的 Quartz,这意味着我们也可以为其他平台开发程序。此外,还有一些独立项目提供额外的程序来简化 GTK 程序的开发。其中一个这样的项目是 Glade。Glade 提供了一个图形界面,可以轻松设计程序前端。一些像 Firefox 这样的项目有它们自己的定制版 GTK。
尽管它最初是用 C 语言编写的,但也有其他语言的绑定,例如 GTKmm 用于 C++、PyGObject 用于 Python 和 gotk3 用于 Golang。
8.2 Qt
Qt 是一个跨平台应用程序开发框架,提供了小部件库和一整套附加功能。与 GTK 不同,Qt 有自己的设计器 QtDesigner 和一个集成开发环境 QtCreator。
此外,它还定义了自己的网络、WebSocket、多媒体、SQL、XML 和 Web 引擎的实现。我们可以很容易地将 Qt 程序移植到其他平台,而无需对源代码进行很少甚至没有修改。因此,它是针对嵌入式和桌面系统软件的首选工具包。
Qt 框架完全用 C++ 语言实现。然而,它也有其他语言的绑定。它定义了自己的标记语言 QML,该语言在语法上类似于 CSS。因此,它赋予我们极大的能力来根据我们的喜好自定义小部件。
一些用 Qt 编写的流行应用程序包括 Autodesk Maya、Autodesk 3ds Max、Crytek CryEngine、DaVinci Resolve 和 K 桌面环境(KDE)。
9、OpenGL的角色
正如我们所看到的,Linux下没有一个官方的本地工具包或GUI库能成为开发GUI应用的万能解决方案。我们看到图形堆栈中的每个模块都有独特的作用。
在大多数情况下,在图形堆栈中,所有的图形指令都通过OpenGL传递。因此,可以肯定地说,我们可以仅基于OpenGL开发一个独立的应用程序。所以,人们可以考虑将OpenGL视为一种在Linux上开发图形应用的本地工具。
举个例子,我们可以看看Blender,这是一个跨平台的3D建模和动画工具。Blender不依赖于其他GUI工具包和低级客户端库,但它有自己的完全基于OpenGL的小部件库。
10、总结
在本文中,我们讨论了Unix类操作系统上使用的图形堆栈。我们从低级组件开始,逐步探讨到使用整个堆栈来渲染图形的高级GUI工具包。
最后,我们简要讨论了OpenGL作为负责渲染图形应用的本地工具的作用。