本文是《深入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加速处理复杂的几何计算、光影效果等。

工作流程是?

一、应用层调用

  1. 开发者使用图形 API 提供的函数来描述他们想要渲染的场景。包括设置状态(VkPipeline)、加载数据(VkBuffer)、使用绘制指令(vkCmdDraw)。
  2. 程序将渲染指令记录到缓冲区(VkCommandBuffer)中。

二、驱动层优化与转换

  1. 显卡驱动介入工作,开始实时追踪API调用时的状态机转换(OpenGL、DX11等传统状态机API特有的过程,下文同义)。
  2. 驱动程序将API调用的指令(SPIR-V、HLSL等中间语言)翻译为显卡支持的指令集,并进行优化(JIT)。
  3. 尝试对指令进行批处理(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 架构的核心理念是:

  1. 预先编译状态 (Immutable State): V k P i p e l i n e VkPipeline VkPipeline 是一个静态、不可变的状态,一旦创建,改变状态需要创建新的管线。
  2. 显式同步 (Explicit Synchronization): 开发者必须使用 V k F e n c e VkFence VkFence V k S e m a p h o r e VkSemaphore VkSemaphore 来手动管理所有依赖关系。
  3. 底层资源管理 (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 控制器上,用于高速数据拷贝,不占用着色器资源。
  • 功能联系核心 —— 异步计算 (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 上的读写冲突或图形损坏。
    • DCC (Delta Color Compression): 驱动程序会在创建 V k I m a g e VkImage VkImage 时,根据标志位决定是否启用 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 内的线程快速交换数据,无需通过显存,极大提升了并行效率。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐