Linux的渲染与显示系统链路
前言:
作者之前一直在做跨平台、全平台SDK(PC、移动端、web等),以前由于业务等在Linux上需求不是太多,所以在这一块的研究与总结较少。现在正好有一个实际来实现与总结Linux系统上的渲染与显示链路,包括linux内核中的各种各样的名称与概念。
传统Linux图形栈(X11/Wayland)的OpenGL实现存在两大痛点:
- 权限控制颗粒度粗:X Server作为中间层持有所有GPU资源,应用只能通过间接请求获取渲染权限。
- 合成器性能损耗:Wayland合成器需要额外拷贝帧数据,难以满足低延迟渲染需求。
EGL on DRM(或 DRM/KMS + EGL 直连)应用直接打开 DRM 设备、GBM 分配 Buffer、EGL 绑定 DRM 显示surface,opengl/opengles/vulkan等图形API渲染绘制帧,最后直接刷帧到 KMS上屏。
优点:
一、消耗低(X11、Wayland各种服务与进程消耗资源高)
二、链路短、延迟低:
Wayland链路:App → EGL → Mesa → 共享Buffer → 合成器拷贝/合成 → KMS
DRM+GBM+EGL 直出链路:App → EGL → GBM分配BO → DRM/KMS直接提交页翻转(PageFlip)
缺点:
一、只适用于单设备独占屏显示,KMS 的 CRTC / 显示输出同一时间只能由一个进程打开占用。
二、很原始没有生态工具,没有窗口组件,输入要全套接管,没有操作系统级别的图形兜底,比如开机、关机、休眠后唤醒等系统操作都要实现并且要与BSP、操作系统等衔接好。

窗口系统-X11:
GLX是OpenGL Extension to the X Window System的缩写。它作为x的扩展,是x协议和X server的一部分,已经包含在X server的代码中了。GLX提供了xwindow system使用的OpenGL接口,允许通过x调用OpenGL库。OpenGL 在使用时,需要与一个实际的窗口系统关联起来。其实现在GLX已经基本上很少使用了因为GLX必须依赖X11服务上,在不同平台上有不同的机制以关联窗口系统,在Windows上是WGL,在Linux上是GLX,在 Apple OS上是AGL等。
EGL则是OpenGL ES在嵌入式平台上(WGL,GLX,AGL)的等价物。EGL假设OS会提供窗口系统,但EGL与平台无关,并不局限于任何特定的窗口系统,所有用到本地窗口系统的地方都用屏蔽指针来处理,我觉得这就是它易于移植的关键。
X Window System(常简称 X11 或 X)是类 Unix 平台经典的窗口系统,采用 C/S(Client/Server)架构,X11 中的 X 指的就是 X 协议,11 指的是采用 X 协议的第 11 个版本。该架构天然具备网络透明性(Network Transparency),X 协议由 X server 和 X client 组成,配套组件包含窗口管理器(Window Manager)与显示管理器(Display Manager)。
核心架构组件
- X Client(X 客户端)即各类图形应用程序(如 gedit、Firefox、终端模拟器等)。Client 本身不直接操作显示硬件,而是通过 X11 协议向 X Server 发送绘图指令(Drawing Requests)与输入请求。
- X Server(X 服务端)运行在本地(或直接连接显示设备的机器上),是硬件资源的唯一管理者。其核心职责包括:
- 资源管理:接管显卡、显示器、键盘、鼠标等 I/O 设备;
- 渲染输出:解析 Client 的协议请求,完成像素级渲染并输出到屏幕;
- 事件分发:将硬件输入事件(按键、鼠标移动等)路由回传给对应的 X Client。


Linux 本身是没有图形化界面的,所谓的图形化界面系统只不过中是Linux 下的应用程序(跟Win哲学不一样,win是图形界面写到内核中去捆绑在一起)。这一点和 Windows 不一样。Windows 从Windows 95 开始,图形界面就直接在系统内核中实现了,是操作系统不可或缺的一部分。
许多时候 X server 和 X client 在同一台主机上,台式机这看起来没什么。但是X server 和 X client 完全可以运行在不同的机器上,只要彼此通过 X 协议通信即可。于是,我们就可以做一些"神奇"的事情,比如像本文上面谈到的,在本地显示 (X server),运行在服务器上的 GUI 程序 (X client)。这样的操作可以通过 SSH X11 Forwarding (转发) 来实现。
窗口系统-Wayland
Wayland是轻量级窗口系统(无X Server中间层,由Compositor直接管理窗口合成)。Wayland原生支持EGL,流程更简洁表现在: X11 里角色是拆开的:X Server(管绘图原语、窗口树、输入)+ Window Manager(独立的普通客户端,管装饰和布局)+ Compositor(又是另一个客户端,借用 Composite 扩展把窗口重定向到离屏 pixmap 再合成上屏)。三者之间靠 X protocol 互相通信,全局状态一大堆。Wayland 把这三者合并成一个 Compositor:它既是显示服务器,又是窗口管理器,又是合成器。
一句话:Wayland是省掉了 X11 里那次 Composite 重定向 + 二次合成

Wayland 的渲染方式:
在 Wayland 架构中,客户端负责窗口内容的渲染,可以使用软件渲染或硬件渲染(如 OpenGL)。客户端将渲染结果存储在缓冲区中,并通知合成器使用该缓冲区进行屏幕合成。
Wayland 更安全:X11 假设所有客户端可信( 任何应用都可以注册全局键盘钩子),任意程序可监听/注入他人键鼠事件、截取全屏,键盘记录器几乎零门槛,所以在X11下实现录屏与共享桌面非常容易(跟linux的安全哲学不符合的)。
输入隔离:在 Wayland 中,只有 Compositor 知道哪个窗口获得了焦点。Compositor 只会把键盘事件发送给当前获得焦点的那个 Client。其他后台程序无法窃听的按键(做了隔离)。
内容隔离: 个客户端无法直接读取另一个客户端的窗口内容(无法随意截屏)。如果需要截屏,必须通过 Compositor 提供的特定 Portal 接口(如 XDG Desktop Portal),这通常会弹出一个系统级的确认框询问用户是否允许。
要想了解更多详细的Wayland 内容可以查看如下的文章:万字长文详解 Wayland 协议、架构-CSDN博客
EGL
EGL 是 Khronos Group 制定的跨平台图形标准接口,核心定位是作为 OpenGL ES、OpenVG 等渲染 API 与操作系统原生窗口系统之间的适配桥梁。
OpenGL 及 OpenGL ES 作为纯图形渲染 API,仅负责通过驱动向 GPU 下发渲染指令、控制图形渲染管线状态机的运行逻辑,本身不具备与原生窗口系统、显示硬件交互的能力。在 EGL 出现之前,不同平台各自实现了专属的渲染桥接层 ------ 例如 X11 平台的 GLX、Windows 平台的 WGL,均与特定系统深度绑定;而 EGL 以平台无关的设计目标,为渲染 API 对接原生窗口系统提供了统一的标准化方案。
EGL 提供了以下核心机制:
- 对接设备原生窗口系统,管理显示连接的建立与销毁
- 查询绘图表面的可用类型,配置帧缓冲像素格式与参数
- 创建并维护可绘制表面,作为渲染输出的载体
- 在 OpenGL ES 与其他图形渲染 API 之间实现渲染时序同步
- 管理纹理贴图等共享渲染资源,支撑多上下文、多 API 资源交互
为了让OpenGL ES能够绘制在当前设备上,我们需要EGL作为OpenGL ES与设备的桥梁。
EGL API 是独立于 OpenGL ES 各版本标准的独立的一套 API,其主要作用是为 OpenGL 指令 创建 Context 、绘制目标 Surface 、配置 FrameBuffer 属性、Swap 提交绘制结果 等。
EGL 中大部分函数成功时都是返回 EGL_TRUE,失败返回 EGL_FALSE ;具体错误类型可通过 eglGetError() 接口查询。
创建:建立本地系统和 OpenGL ES 的连接 displayId 指定显示连接,一般使用默认的 EGL_DEFAULT_DISPLAY,即返回与默认原生窗口的连接。
EGL 三大核心抽象
EGL 渲染环境的构建围绕三个核心对象展开:
a:Display(EGLDisplay) 是对实际显示设备的抽象,代表 EGL 与原生窗口系统的一个连接实例。初始化的第一步便是建立与本地系统的显示连接,通常调用 eglGetDisplay() 获取句柄,传入 EGL_DEFAULT_DISPLAY 即可关联系统默认显示设备。
b:Surface(EGLSurface)是对用来存储图像的内存区域FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer,是 OpenGL ES 渲染指令的直接绘制目标。
c:Context (EGLContext) 存储 OpenGL ES 渲染管线全部状态信息的上下文容器,涵盖当前着色器程序、纹理绑定状态、顶点数组配置、渲染参数等所有运行时状态。EGLContext 必须绑定到有效 EGLSurface 上,才能正常执行渲染指令。
内核之DRM&KMS&GDM:
在 Linux 图形显示栈中,DRM、KMS 与 GDM 分处内核态 与用户态的不同层级,串联起从硬件驱动到用户登录会话的完整链路:
- DRM(Direct Rendering Manager):内核级图形子系统,统一管理 GPU 显存、渲染命令调度与设备访问,是整个图形栈的基石。
- KMS(Kernel Mode Setting):DRM 的显示分支,以 framebuffer、plane、CRTC、encoder、connector 等对象抽象输出管线,分辨率、刷新率等显示模式的配置与提交。
- GDM(GNOME Display Manager):用户态显示管理器,负责图形登录界面的呈现、PAM 身份认证,以及用户会话的创建、切换与销毁。
三者的调用关系是严格分层的:内核层 DRM/KMS 提供硬件抽象 → 用户态显示服务器(Mutter、Xorg 等)封装驱动接口并独占 DRM Master → GDM 拉起并管理显示服务器会话,在其上实现登录交互与会话生命周期管理。

DRM (Direct Rendering Manager)
DRM的核心功能模块
| 模块 | 功能描述 |
|---|---|
| GEM (Graphics Execution Manager) | GPU 内存管理器,负责显存分配、缓冲对象 (BufferObject) 管理、内存映射与释放,是硬件加速渲染的基础 |
| KMS (Kernel Mode Setting) | 内核态显示模式设置,接管显示输出的全流程配置 |
| PRIME / DMA-BUF | 跨设备缓冲共享机制,支持 GPU 与其他硬件(如摄像头、编解码器)之间零拷贝数据传输 |
| GPU 调度器 | 统一管理 GPU 命令提交、任务队列与优先级调度(drm_gpu_scheduler) |
| 同步原语 | Fence、VBlank 等同步机制, 解决的是"CPU 和 GPU 谁等谁、什么时候等"的时序问题,目的是对齐渲染节奏与显示刷新,避免撕裂和卡顿。保证渲染与显示时序一致,避免画面撕裂 |
设备节点与权限模型:
DRM 通过 /dev/dri/ 目录下的设备节点向用户态暴露接口:
- /dev/dri/cardX:主设备节点(Primary Node),用于模式设置与特权操作,只有 DRM Master 进程(只有一个)可执行 KMS 配置。可以是card0 card1 、card2等
- /dev/dri/renderDX:渲染节点(Render Node),非特权渲染接口,普通用户可直接调用进行 3D 渲染、视频编解码等操作,无需 DRM Master 权限。
KMS (Kernel Mode Setting)
KMS 是 DRM 框架内专门负责显示输出的子系统,将原本运行在用户态的显示模式配置逻辑移入内核,由内核统一管理显示硬件资源,实现:
| 对象 | 本质 | 核心职责 | 关键约束 |
|---|---|---|---|
| Framebuffer | 一块像素存储 | 承载像素数据,绑定 format / modifier / stride / 宽高,作为 Plane 的数据源 | 对一块显存的视图/元数据描述(drm_framebuffer),底层可以来自 GEM BO,也可以是导入的 dma-buf。 |
| Plane | 硬件图层 | 从 Framebuffer 取像素,决定位置、尺寸、缩放、Z 序、透明度 | 分 Primary(基础画面)、Cursor(硬件鼠标)、Overlay(视频/UI 叠加);多 Plane 可挂同一 CRTC 由硬件合成 |
| CRTC | 显示管线调度器 | 生成像素时钟与 HSync/VSync 时序,决定分辨率与刷新率,驱动扫描输出 | 数量决定可同时驱动的独立显示管线数 |
| Encoder | 信号编码器 | 把 CRTC 的并行像素时序转成 HDMI/DP/VGA 的串行电气信号 | 硬件中间层,用户态一般不直接配置,由驱动自动路由 |
| Connector | 物理端口抽象 | 检测热插拔、读取 EDID、枚举支持的显示模式 | Connector 通过一个 Encoder 连接到 CRTC;一个 Connector 在硬件上可能支持多个可选 Encoder,但同一时刻只使用一个。 |
GDM (GNOME Display Manager)
定位与职责:GDM 是 GNOME 桌面环境的官方显示管理器,属于用户态系统服务,运行在 DRM/KMS 与显示服务器之上,核心职责包括:
- 提供图形化登录界面(Greeter),处理用户身份认证
- 管理 X11 与 Wayland 显示会话的启动、切换与销毁
- 控制用户登录后的桌面环境加载流程
- 支持多用户切换、远程桌面接入、自动登录等高级功能
Mesa:
在linux的图形就不得不提起:Mesa(全称 Mesa 3D Graphics Library)是一个开源的用户空间图形库,它的核心作用是在操作系统中实现各种图形 API,比如 OpenGL、Vulkan、OpenGL ES、EGL,以及早期的 Direct3D 9(通过 Gallium Nine)等。简单来说,当你的程序调用 glDrawArrays 或 vkQueueSubmit 时,真正把这些高级 API 指令翻译成 GPU 能理解的硬件命令的,往往就是 Mesa。
支持各大平台,其中linux上是主流的开源图形栈,Windows 和 macOS 上也能跑 Mesa,但市场占有率很低------不过这并不妨碍 Mesa 的软光栅实现(当然不妨碍Mesa的软光栅LLVpipe、Lavapipe实现vulkan、opengl在win上做兜底方案)

Linux 上开源显卡驱动的用户态部分UMD,内核是 DRM,Mesa 运行在用户空间,是图形 API 与内核图形驱动之间的转换层。
UMD(User Mode Driver,用户模式驱动):位于 Mesa 中,负责 API 状态机、着色器编译等。
KMD(Kernel Mode Driver,内核模式驱动):位于 Linux 内核中,如 amdgpu、i915 等,负责硬件资源管理。
Mesa的软件架构:
Mesa 内部有两套驱动框架目前主流的开源驱动基本都基于 Gallium3D。Mesa Classic:经典驱动架构,各驱动独立实现较多逻辑
Gallium3D:现代驱动架构,多个驱动共享通用中间层,便于维护和功能统一。
在编译管线中,Mesa 还涉及多种中间表示(IR),整个流程可以理解为:高级着色器语言->某IR(GLSL IR/SPIR-v)->驱动特定优化->GPU机器码。
Mesa 的两套纯软光栅实现
Mesa 内置的两套软件光栅化器,都是纯 CPU 实现+SIMD(加速)、不依赖任何 GPU 硬件,作为无显卡 / 驱动异常时的兜底方案:
- llvmpipe:面向 OpenGL / OpenGL ES 的软件渲染器,基于 LLVM JIT 编译着色器,利用CPU SIMD指令加速,是目前 Linux 无 GPU 环境下的标准 GL 兜底实现,替代了更早的 softpipe。
- lavapipe:面向 Vulkan 的软件渲染器,可理解为 llvmpipe 的 Vulkan 版本,同样基于 LLVM 后端,用于在无 GPU 环境下兼容 Vulkan 应用。
对于PC端:
Intel:全面拥抱 Mesa 主线;( Intel 核显(UHD/Iris Xe)的官方主力驱动就是 Mesa 主线的开源实现)
AMD:Mesa 开源驱动为消费级主流
NVIDIA:开源社区驱动为 Nouveau,NVIDIA 专有驱动则绕过 Mesa,提供独立的 OpenGL/Vulkan 实现
Home --- The Mesa 3D Graphics Library
参考资料:
https://www.cnblogs.com/yongdaimi/p/11244950.html
https://blog.csdn.net/afei__/article/details/84867104
OpenGL与X11/Wayland/DRM/KMS/EGL的关系_opengl x11-CSDN博客