阅读随笔 | 深入Linux GPU ep3 图形API与Vulkan初探
摘要 本文介绍了Linux环境下AMD GPU的图形渲染与AI技术实践,重点解析了图形API的作用与工作流程。图形API(如OpenGL、Vulkan)作为硬件抽象层,封装显卡指令,提供跨平台支持和高性能渲染。Vulkan作为现代低开销API,采用显式资源管理和同步机制,与AMD GPU硬件架构高度契合,通过队列、资源和并行优化实现高效图形处理。文章还探讨了Vulkan组件及其与AMD驱动的协作关
本文是《深入Linux GPU AMD GPU渲染与AI技术实践》读书笔记,以通俗简洁的方式重述知识。
干货长文预警,建议您做好准备。
关键词: Linux GPU 计算机图形学
文章目录
导读
书接上文,应用如果想使用硬件绘制图形,大多需要调用图形API(使用图形库)。所谓图形API,就是将底层的硬件交互封装、屏蔽起来,给开发者一套较为简单易用的标准接口用来绘图。
图形API向上接受程序的绘图指令,向下调用显卡驱动并发出翻译后的指令。本章是对于图形API的讲解,向下的细节暂不涉及。
注意:标准与标准的实现往往是分开的。图形API属于前者。图形API的实现,比如Mesa,后文再做解读。
图形API
是什么?
图形API(Application Programming Interface)是一组用于渲染2D/3D图形的编程接口,允许开发者直接调用硬件加速的图形功能。
干什么的?
- 硬件抽象:封装显卡驱动和硬件指令,简化图形渲染流程。
- 跨平台支持:如OpenGL支持多操作系统,DirectX主要针对Windows平台。
- 高性能渲染:通过GPU加速处理复杂的几何计算、光影效果等。
工作流程是?
一、应用层调用
- 开发者使用图形 API 提供的函数来描述他们想要渲染的场景。包括设置状态(VkPipeline)、加载数据(VkBuffer)、使用绘制指令(vkCmdDraw)。
- 程序将渲染指令记录到缓冲区(VkCommandBuffer)中。
二、驱动层优化与转换
- 显卡驱动介入工作,开始实时追踪API调用时的状态机转换(OpenGL、DX11等传统状态机API特有的过程,下文同义)。
- 驱动程序将API调用的指令(SPIR-V、HLSL等中间语言)翻译为显卡支持的指令集,并进行优化(JIT)。
- 尝试对指令进行批处理(OpenGL、DX11)。
三、命令提交、调度与执行
驱动程序将指令提交到命令队列中,随后GPU进行后续操作。有关GPU队列、调度、执行的细节,后续文章会讲解。本文主要聚焦图形API的部分。
现实中有哪些?
DirectX
- 开发者/管理机构: Microsoft (微软)
- 特点:
- 平台限制: 仅限于 Microsoft Windows 和 Xbox 平台使用。
- 捆绑性: 作为 Windows 操作系统的核心组件之一,与 Windows 的版本更新紧密关联。
- 架构: 在不同的版本(如 DirectX 11、DirectX 12)中,架构差异较大。
OpenGL
- 开发者/管理机构: Khronos Group(最初由 Silicon Graphics 推出)
- 特点:
- 跨平台性: 最大的优势,支持 Windows、macOS、Linux、Android、iOS 等几乎所有主流操作系统。
- 开放标准: 顾名思义,它是一个开放的、被广泛接受的标准。
- 架构: 早期版本是状态机模型,对 CPU 的优化不如现代 API,因此在驱动层面的开销可能较大。
Vulkan
- 开发者/管理机构: Khronos Group (与 OpenGL 同一机构)
- 特点:
- 跨平台性: 与 OpenGL 类似,支持 Windows、Linux、Android 等(在 macOS/iOS 上常通过 MoltenVK 间接实现)。
- 架构: 它是被誉为 “OpenGL 的继任者”,采用了底层/低开销 (Low-Overhead) 设计理念。
- 性能提升: 将大量的驱动程序工作(如同步、资源管理)交给了开发者,从而显著减轻了 CPU 负担,更有效地利用多核 CPU,提高渲染性能。
Vulkan API初探
有哪些组件?
Vulkan API 作为一个现代的、低开销的图形 API,其架构设计与传统的 OpenGL 或 DirectX 11 有着显著的不同,它将大量的控制权交给了开发者,开发者需要手动管理之前由驱动程序隐式处理的几乎所有内容,从而实现对 GPU 的最大化利用和多核 CPU 的高效调度。
Vulkan 架构的核心理念是:
- 预先编译状态 (Immutable State): V k P i p e l i n e VkPipeline VkPipeline 是一个静态、不可变的状态,一旦创建,改变状态需要创建新的管线。
- 显式同步 (Explicit Synchronization): 开发者必须使用 V k F e n c e VkFence VkFence 和 V k S e m a p h o r e VkSemaphore VkSemaphore 来手动管理所有依赖关系。
- 底层资源管理 (Low-Level Resource Management): 内存分配和绑定必须由开发者手动完成。
1. 管理组件 (Management Components)
这部分组件负责 Vulkan 环境的初始化、连接硬件以及设置通信通道。
| 组件名称 | 英文/简称 | 作用与特点 |
|---|---|---|
| 实例 | V k I n s t a n c e VkInstance VkInstance | 代表 Vulkan 应用程序的运行时连接。它是应用程序与 Vulkan 库本身交互的起点。它负责管理层(Validation Layers)的设置。 |
| 物理设备 | V k P h y s i c a l D e v i c e VkPhysicalDevice VkPhysicalDevice | 代表系统中的一个硬件设备(如一张 GPU 显卡)。它用于查询设备的能力、队列系列 (Queue Families) 等信息。 |
| 逻辑设备 | V k D e v i c e VkDevice VkDevice | 应用程序与物理设备建立的通信接口。它负责创建所有实际的 Vulkan 对象(如管线、缓冲区、纹理等)。 |
| 队列 | V k Q u e u e VkQueue VkQueue | GPU 上的命令执行点。GPU 任务通常分为图形 (Graphics)、计算 (Compute) 和传输 (Transfer) 等不同队列系列,用于提交命令缓冲区。 |
2. 管线组件 (Pipeline Components)
管线(Pipeline)是 Vulkan 中最重要的概念之一。它描述了图形数据从输入到屏幕输出的完整、不可变的流程。
| 组件名称 | 英文/简称 | 作用与特点 |
|---|---|---|
| 管线 | V k P i p e l i n e VkPipeline VkPipeline | 一个不可变的状态对象,定义了 GPU 上所有阶段的固定功能状态(如混合、深度测试)和可编程着色器(Shader)。 |
| 着色器模块 | V k S h a d e r M o d u l e VkShaderModule VkShaderModule | 封装了 SPIR-V 字节码(Vulkan 的中间表示语言)的模块。在创建管线时,这些模块会被链接到相应的阶段。 |
| 管线布局 | V k P i p e l i n e L a y o u t VkPipelineLayout VkPipelineLayout | 定义了管线可以访问的资源接口,包括描述符集布局 ( V k D e s c r i p t o r S e t L a y o u t VkDescriptorSetLayout VkDescriptorSetLayout) 和推送常量 ( P u s h C o n s t a n t s Push \: Constants PushConstants)。 |
| 渲染通道 | V k R e n d e r P a s s VkRenderPass VkRenderPass | 定义了一组渲染操作(包括颜色、深度、模板附件)的输入、输出和过渡。所有的绘制命令都必须在 V k R e n d e r P a s s VkRenderPass VkRenderPass 内部执行。 |
3. 资源组件 (Resource Components)
这些组件用于管理 GPU 上的数据和内存。开发者必须显式地分配内存并将数据绑定到资源上。
| 组件名称 | 英文/简称 | 作用与特点 |
|---|---|---|
| 图像 | V k I m a g e VkImage VkImage | 代表 2D 或 3D 纹理、渲染目标、深度/模板缓冲区等。它只定义了数据的布局。 |
| 缓冲区 | V k B u f f e r VkBuffer VkBuffer | 存储通用数据(如顶点数据、索引数据、统一缓冲区 U n i f o r m B u f f e r Uniform \: Buffer UniformBuffer 等)的线性内存。 |
| 内存对象 | V k D e v i c e M e m o r y VkDeviceMemory VkDeviceMemory | 物理设备上的实际裸内存块。开发者必须查询内存类型、分配内存,并显式地将缓冲区或图像绑定到这块内存上。 |
| 描述符集 | V k D e s c r i p t o r S e t VkDescriptorSet VkDescriptorSet | 类似于 DirectX 或 OpenGL 中的“资源槽位”。它将管线布局 (Pipeline Layout) 中定义的资源接口,与实际的缓冲区、图像资源关联起来。 |
4. 同步组件 (Synchronization Components)
由于 Vulkan 采用多线程命令提交和异步 GPU 执行模型,同步机制变得至关重要,用于确保操作按正确的顺序执行并正确访问共享资源。
| 组件名称 | 英文/简称 | 作用与特点 |
|---|---|---|
| 命令缓冲区 | V k C o m m a n d B u f f e r VkCommandBuffer VkCommandBuffer | 记录所有 GPU 命令(如绘制、调度、传输)的对象。它在 CPU 上创建,然后提交给队列 ( V k Q u e u e VkQueue VkQueue) 在 GPU 上执行。 |
| 围栏 | V k F e n c e VkFence VkFence | 主要用于CPU 与 GPU 之间的粗粒度同步。CPU 可以等待一个围栏,直到相应的 GPU 命令执行完毕。 |
| 信号量 | V k S e m a p h o r e VkSemaphore VkSemaphore | 主要用于GPU 内部,在不同队列或不同命令缓冲区之间进行细粒度同步。例如,确保渲染操作在呈现操作之前完成。 |
| 事件 | V k E v e n t VkEvent VkEvent | 用于在命令缓冲区内进行非常细粒度的同步。GPU 可以设置或等待一个事件,允许更灵活和动态的同步。 |
怎么与AMD GPU驱动合作?
Vulkan API 与 AMD GPU 驱动之间的联系是“映射”与“翻译”的关系。
由于 Vulkan 的设计初衷很大程度上受到了 AMD Mantle API 的启发,它与 AMD 的 GCN(Graphics Core Next)及 RDNA 架构有着天然的契合度。AMD 驱动程序不再像 OpenGL 时代那样充当“保姆”或“猜测者”,而是充当一个极薄的转换层,将 Vulkan 的显式指令直接映射到 AMD 的硬件单元上。简而言之,Vulkan 是控制台,AMD 驱动是极简的翻译器,AMD GPU 是执行工厂。
以下从 队列(Queues)、资源(Resources) 和 并行(Parallelism) 三个维度详细分析这种功能联系:
1. 队列 (Queues) 与 硬件调度器
Vulkan 的队列系统(Queue Families)与 AMD GPU 的硬件调度单元有着直接的物理对应关系。
- Vulkan 层面:
- Vulkan 暴露了不同类型的队列族(Queue Families),主要包括:图形 (Graphics)、计算 (Compute) 和 传输 (Transfer/Copy)。
- 开发者通过
vkQueueSubmit将命令提交给这些队列。
- AMD 驱动与硬件映射:
- ACE (Asynchronous Compute Engines): AMD GPU 硬件内部拥有专门的 ACE 单元。AMD 驱动程序会将 Vulkan 的计算队列 ( V k Q u e u e VkQueue VkQueue with
COMPUTE_BIT) 直接映射到这些 ACE 上。 - GCP (Graphics Command Processor): Vulkan 的图形队列被映射到 GCP 上。
- DMA 引擎: Vulkan 的传输队列被映射到硬件的 DMA 控制器上,用于高速数据拷贝,不占用着色器资源。
- ACE (Asynchronous Compute Engines): AMD GPU 硬件内部拥有专门的 ACE 单元。AMD 驱动程序会将 Vulkan 的计算队列 ( V k Q u e u e VkQueue VkQueue with
- 功能联系核心 —— 异步计算 (Async Compute):
这是 AMD 驱动与 Vulkan 结合最紧密的地方。AMD 驱动允许同时向 Graphics Queue 和 Compute Queue 提交任务。硬件调度器(HWS)能够并行执行这两类任务:- 当图形管线(如光栅化)正在忙碌但并未占满所有计算单元(CU/WGP)时,ACE 会利用空闲的计算单元去处理 Vulkan 计算队列中的任务(如物理模拟、后期处理)。
- 结果: 极大提高了 GPU 的利用率,填补了流水线气泡。
2. 资源 (Resources) 与 显存管理
Vulkan 放弃了驱动层的隐式内存管理,要求开发者显式控制,这使得 AMD 驱动可以将底层的内存架构直接暴露给应用。
- Vulkan 层面:
- 对象: V k D e v i c e M e m o r y VkDeviceMemory VkDeviceMemory(显存块)、 V k B u f f e r VkBuffer VkBuffer(缓冲)、 V k I m a g e VkImage VkImage(图像)。
- 同步:管线屏障 ( V k C m d P i p e l i n e B a r r i e r VkCmdPipelineBarrier VkCmdPipelineBarrier) 和 布局转换 ( I m a g e L a y o u t T r a n s i t i o n ImageLayoutTransition ImageLayoutTransition)。
- AMD 驱动与硬件映射:
- 堆 (Heaps) 的暴露: AMD 驱动通过
vkGetPhysicalDeviceMemoryProperties直接暴露显卡的物理内存堆,例如 Device Local (高速显存 VRAM) 和 Host Visible (CPU 可见内存,利用 PCIe BAR 大小调整技术,即 SAM/Re-Size BAR)。 - 虚拟地址空间: 驱动负责维护 Vulkan 逻辑地址到 GPU 物理地址的页表映射。
- 屏障与缓存控制 (The Crucial Link):
- 当开发者在 Vulkan 中设置一个管线屏障(例如,等待片元着色器写完,再让计算着色器读)时,AMD 驱动将其翻译为特定的硬件指令,如
WAIT_REG_MEM或缓存刷新指令(Cache Flush/Invalidate)。 - AMD 的 RDNA 架构非常依赖这种显式同步。驱动不再猜测何时刷新缓存,而是完全依赖 Vulkan 指令。如果开发者屏障设置错误,就会直接导致 AMD GPU 上的读写冲突或图形损坏。
- 当开发者在 Vulkan 中设置一个管线屏障(例如,等待片元着色器写完,再让计算着色器读)时,AMD 驱动将其翻译为特定的硬件指令,如
- DCC (Delta Color Compression): 驱动程序会在创建 V k I m a g e VkImage VkImage 时,根据标志位决定是否启用 AMD 专有的色彩压缩技术来节省带宽。
- 堆 (Heaps) 的暴露: AMD 驱动通过
3. 并行 (Parallelism) 与 指令执行
Vulkan 的并行体现在两个层面:CPU 端的命令记录并行,和 GPU 端的指令执行并行。
- CPU 端并行(多线程录制):
- Vulkan 机制: 多个 CPU 线程可以同时向不同的 V k C o m m a n d B u f f e r VkCommandBuffer VkCommandBuffer 录制命令。
- AMD 驱动作用: 由于 Vulkan 驱动去除了全局锁(Global Lock)且不再进行复杂的错误检查(Validation),AMD 驱动在
vkCmdDraw等调用中的 CPU 开销极低。这使得 AMD CPU + AMD GPU 的组合在 Vulkan 游戏中往往能表现出极佳的多核缩放性能。
- GPU 端并行(着色器执行):
- SPIR-V 到 ISA 的编译: 开发者提交的是 SPIR-V(中间码)。AMD 驱动中的编译器组件负责将其编译为 ISA (Instruction Set Architecture),即 GCN 或 RDNA 汇编代码。
- Wavefronts (波前):
- AMD GPU 以 Wavefront(通常是 32 或 64 个线程一组)为单位执行指令。
- 驱动程序分析 Vulkan 的 V k P i p e l i n e VkPipeline VkPipeline 和 Shader,优化寄存器(VGPR/SGPR)的使用量,以决定在每个计算单元(CU)上能同时运行多少个 Wavefront(即 Occupancy,占用率)。
- 子组操作 (Subgroup Operations): Vulkan 的 Subgroup 特性直接对应 AMD 硬件的 Cross-Lane Operations(线程间通信),允许一个 Wavefront 内的线程快速交换数据,无需通过显存,极大提升了并行效率。
更多推荐



所有评论(0)