阅读随笔 | 深入Linux GPU ep4 用户空间图形库详解:以Mesa为例
本文是《深入Linux GPU AMD GPU渲染与AI技术实践》的读书笔记,重点介绍了Linux系统中GPU渲染的实现架构。主要内容包括: MesaGallium3DVulkan ICD
本文是《深入Linux GPU AMD GPU渲染与AI技术实践》读书笔记,以通俗简洁的方式重述知识。
干货长文预警,建议您做好准备。
关键词: Linux GPU 图形栈
导读
书接上文,我们已经讲完了图形API从接受应用程序发出的绘图命令,到向显卡发出具体指令的理论过程。本章内容将从Mesa的实现出发,看看这个过程在Linux中是如何实现的。如果说前文讲的是标准,那么本章主要关注标准的实现
Mesa
Mesa是一个在开源环境下实现多种图形和计算 API 规范的软件库。
核心角色: 它是 Linux、FreeBSD、Android 等系统上事实上的 OpenGL 和 Vulkan 驱动实现。
Mesa 实现了 Khronos Group(科纳斯组织)发布的许多标准,包括:
OpenGL (所有版本,包括桌面版和 OpenGL ES 移动版)
Vulkan (作为可安装客户端驱动程序 ICD)
OpenCL (计算 API)
EGL (用于窗口系统接口的 API)
VDPAU/VA-API (视频加速 API)
简单来说,当一个 Linux 应用程序调用 glDraw* 或 vkCreate* 函数时,它实际上是在调用 Mesa 库中的代码。
架构与组件
Mesa 的架构是分层的,主要由API 前端、核心抽象层和硬件后端组成。
简而言之,Vulkan调用走ICD,OpenGL调用走Gallium3D框架。
API 前端 (State Trackers / ICDs)
这层是面向应用程序的,负责解析上层 API 的调用。因为OpenGL是基于状态机的,所以需要State Tracker隐式维护状态机。
- State Trackers (状态跟踪器): 负责 OpenGL 和 OpenCL 等 API。它们将 API 调用(如状态设置、数据绑定、绘制指令)转换为 Mesa 内部的通用数据结构和命令。
- Vulkan ICDs (可安装客户端驱动): Vulkan 驱动在 Mesa 中是独立实现的,如:
- RADV: 针对 AMD Radeon GPU 的 Vulkan 驱动。
- ANV: 针对 Intel GPU 的 Vulkan 驱动。
硬件后端 (Drivers)
这层是与特定 GPU 硬件交互的代码,向上提供抽象层所需的接口,向下生成控制硬件的命令。
| 驱动名称 | 对应硬件 | 抽象层 |
|---|---|---|
| Iris / Crocus | Intel Gen8+ GPU | Gallium3D |
| RadeonSI | AMD Radeon GCN/RDNA 架构 | Gallium3D |
| RADV | AMD Radeon GCN/RDNA 架构 | Vulkan ICD |
| ANV | Intel Gen8+ GPU | Vulkan ICD |
| Nouveau | NVIDIA GPU (性能受限) | Gallium3D |
4. 与内核的交互 (libdrm)
Mesa 位于用户空间,但 GPU 硬件控制、内存分配和命令提交等关键任务必须在内核空间完成。
libdrm 负责将 Mesa 生成的硬件命令和内存请求,通过系统调用传递给 Linux 内核中的 DRM 模块(例如:amdgpu 或 i915 驱动)。
Gallium3D
Gallium3D 是 Mesa 3D 图形库内部的一个图形驱动程序架构/框架。
它试图定义一套通用的、面向硬件的接口,让所有 OpenGL 驱动程序(无论是针对 AMD、Intel 还是其他硬件)都实现这套相同的接口。这样编写新的硬件驱动时,只需要编写新的硬件后端,而无需重新实现整个 OpenGL 状态机和优化逻辑。
简而言之,就是在硬件与OpenGL之间提供一层抽象,将硬件实现与OpenGL的逻辑解耦。
组件
State Trackers (状态跟踪器)
- 负责接收应用程序的 gl* 调用。
- 维护 OpenGL 的状态机(如当前的颜色、混合模式、深度测试设置等)。
- 负责将特定的 API(如 OpenGL、OpenCL、DirectX 9)的调用,转换为 Gallium3D 内部定义的通用图形原语和命令。
- 它将这些 Gallium3D 抽象接口可以理解的调用传递给下一层。
Hardware Drivers (硬件驱动/后端)
- 针对特定的 GPU 硬件,实现 Gallium3D 抽象层定义的所有接口。
- 负责与 libdrm 通信,并将 Gallium3D 抽象命令最终翻译成 GPU 硬件能理解的指令集和命令缓冲区。
工作过程
Gallium3D 的核心是定义了一个面向服务的架构,将复杂的 OpenGL 状态机拆解成一系列简单的、可插拔的服务或对象。这个架构的核心是 pipe_context 和 pipe_screen 接口。
pipe_screen(硬件抽象): 负责描述和查询 GPU 的静态能力(如支持的纹理格式、最大缓冲区大小、着色器模型版本等)。每个硬件驱动(后端)都必须实现这个接口。pipe_context(渲染上下文): 负责描述和管理动态渲染状态。OpenGL 的所有绘制和状态设置指令最终都通过这个上下文接口下发。
一、状态跟踪与 API 转换(API 前端)
这是由 Mesa 中的 OpenGL State Tracker 完成的。
- 拦截 OpenGL 调用:
应用程序调用标准的 OpenGL 函数(如glBegin(),glColor(),glTexImage2D(),glDrawArrays()等)。 - 维护抽象状态:
State Tracker 不会将每个gl*调用立即转发给硬件。相反,它会维护一套抽象的、规范化的 OpenGL 状态。 - 状态对象化 (State Object Generation):
Gallium3D 鼓励将大量的 OpenGL 状态(如深度/模板/混合状态、光栅化状态、视口设置)打包成不可变的 Gallium3D 状态对象。- 例如,OpenGL 中对混合、深度和模板测试的设置,会被 State Tracker 转换为一个统一的 Gallium3D
pipe_blend_state结构体。
- 例如,OpenGL 中对混合、深度和模板测试的设置,会被 State Tracker 转换为一个统一的 Gallium3D
- 调用抽象接口:
当状态发生变化或需要绘制时,State Tracker 调用pipe_context提供的统一接口,而不是直接调用硬件特定的函数。- 设置状态:
pipe_context->set_blend_state(pipe_blend_state) - 绘制:
pipe_context->draw_vbo(...)
- 设置状态:
二、数据与资源抽象(资源管理)
Gallium3D 对所有图形资源进行了统一抽象,使得驱动程序无需关心 OpenGL 中复杂的资源绑定细节。
- 统一资源对象:
无论是 OpenGL 的纹理、顶点缓冲区还是帧缓冲区,在 Gallium3D 内部都被抽象为通用的pipe_resource对象。 - 映射与传输:
应用程序对资源的读写操作(如glMapBuffer)被转换为pipe_context->transfer_map()和pipe_context->transfer_unmap()等抽象接口。这允许驱动程序在不同的内存模型(主机内存、设备内存)之间进行高效的数据传输。 - 着色器抽象:
- OpenGL 的 GLSL 着色器首先被编译成 Gallium3D 内部的通用中间表示 (Intermediate Representation)。
- 然后,由硬件后端驱动(如 RadeonSI)将这个中间表示编译成其 GPU 硬件的指令集架构 (ISA)。
三、命令翻译与提交(硬件后端)
这是由特定硬件的 Gallium3D 驱动(如 RadeonSI)完成的。
- 接收抽象调用:
驱动后端接收到来自pipe_context的抽象 API 调用(如set_blend_state)。 - 翻译成硬件命令:
驱动后端的核心任务是将抽象状态和命令翻译成该 GPU 硬件能够识别的寄存器设置、命令包 (Command Packet) 和指令流。- 例如,一个抽象的
pipe_blend_state对象会被 RadeonSI 驱动翻译成一系列写入 AMD GPU 硬件寄存器的值,以配置其融合单元 (Blend Unit)。
- 例如,一个抽象的
- 命令缓冲区生成:
驱动将这些硬件命令写入一个或多个命令缓冲区。 - 提交到内核:
驱动程序通过 libdrm 接口,将完成的命令缓冲区提交给 Linux 内核的 DRM 模块,由内核调度到 GPU 硬件执行。
Vulkan ICD(RADV、ANV)
ICD (Installable Client Driver): 可安装客户端驱动程序。ICD 是 Vulkan API 的实际硬件实现。通常是以共享库(在 Windows 上是 .dll 文件,在 Linux 上是 .so 文件)的形式存在的,它包含了所有用于将 Vulkan API 调用转化为特定硬件指令的代码。
如果系统上有 NVIDIA、AMD 和 Intel 三张显卡,那么安装了三个独立的 Vulkan ICD。
架构
在 Vulkan 的运行时环境中,ICD 位于 Vulkan 加载器 (Vulkan Loader) 之下,位于硬件驱动之上。
Application → API Calls Vulkan Loader → Dispatch Vulkan ICD → Hardware I/O GPU Driver / Kernel \text{Application} \xrightarrow{\text{API Calls}} \text{Vulkan Loader} \xrightarrow{\text{Dispatch}} \text{Vulkan ICD} \xrightarrow{\text{Hardware I/O}} \text{GPU Driver / Kernel} ApplicationAPI CallsVulkan LoaderDispatchVulkan ICDHardware I/OGPU Driver / Kernel
Vulkan 加载器 (Vulkan Loader)
加载器(如 Khronos 维护的 v u l k a n vulkan vulkan-loader)是应用程序首次调用 Vulkan 函数时接触到的第一个组件。
功能: 加载器负责:
1. 发现 ICD: 扫描系统路径和注册表,找到所有已安装的 ICD(即,找到系统中所有可用的 GPU 驱动)。
2. 函数分发 (Dispatch): 维护一个巨大的函数指针表。当应用程序调用一个 Vulkan 函数时,加载器通过这个表将调用转发给正确的 ICD 实例。
3. 管理层 (Layers) 插入: 负责将验证层 (Validation Layers) 和工具层插入到调用链中。
Vulkan ICD
ICD 扮演了“翻译家”和“执行者”的角色。
- 功能: 接收来自加载器的函数调用,并执行将 Vulkan 逻辑转化为 GPU 特定指令的实际工作。
工作原理
ICD 的实现原理基于 Vulkan 的模块化、可扩展和函数指针分发的设计。
函数指针分发机制 (Dispatch Table)
这是 Vulkan ICD 运行的核心机制,它允许 Vulkan API 在运行时动态地绑定到正确的驱动程序函数。
- 入口点 (Entry Points): 当应用程序调用一个 Vulkan 函数时,它首先调用的是加载器导出的函数(例如
$vkCreateInstance$)。 - 分发调用: 加载器维护着不同层次的分发表 (Dispatch Table):
- Instance Dispatch Table ( V k I n s t a n c e VkInstance VkInstance): 包含全局函数和实例相关的函数(如层和扩展)。
- Device Dispatch Table ( V k D e v i c e VkDevice VkDevice): 包含设备相关的函数(如命令提交、管线创建)。
- ICD 填充表格: 当加载器初始化一个 ICD 时,ICD 会将自己实现的 Vulkan 函数地址(如
$vkCreatePipeline$的驱动版本)填充到相应的分发表中。 - 最终调用: 当应用程序调用
$vkCreatePipeline$时,加载器通过设备分发表,直接调用 ICD 中对应的实现函数。
ICD 的核心内部工作
ICD 内部的代码负责将抽象的 Vulkan 概念转化为硬件命令。
- 对象转换: ICD 接收 Vulkan 抽象对象(如 V k P i p e l i n e VkPipeline VkPipeline、 V k C o m m a n d B u f f e r VkCommandBuffer VkCommandBuffer),并将其转换为硬件能够识别的私有驱动结构体。
- 着色器编译: ICD 接收 SPIR-V 格式的着色器代码,并使用驱动内部的编译器将其翻译成 GPU 特定的 ISA (指令集架构)。例如,AMD 的 RADV ICD 会将 SPIR-V 编译成 RDNA/GCN 汇编指令。
- 命令缓冲区生成: ICD 将 Vulkan 绘制、调度和传输命令(如 v k C m d D r a w vkCmdDraw vkCmdDraw) 转化为硬件专用的命令流(或称为“环形缓冲区”中的数据包)。
- 内核通信: ICD 利用底层的系统接口(如 Linux 上的 libdrm 库)将生成的命令流提交给内核中的 GPU 驱动,最终由内核驱动程序将这些指令送入 GPU 的硬件队列执行。
现实中的ICD
| ICD 名称 | 对应的 Mesa 驱动 | 目标硬件 | 特点 |
|---|---|---|---|
| RADV | Radeon Vulkan | AMD Radeon GPU | 非常成熟且性能优秀,是 Valve (Steam Deck) 等使用的主要驱动。 |
| ANV | Intel ANV | Intel GPU | 针对 Intel 核显的实现,同样成熟。 |
| V3DV | V3D Vulkan | Raspberry Pi / Broadcom | 针对嵌入式/低功耗硬件的 Vulkan 实现。 |
更多推荐

所有评论(0)