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