中EN
概念页

图形 API 设备、管线状态与资源

Graphics API Devices, Pipeline State & Resources

所有图形 API(OpenGL、DirectX、Vulkan、Metal)都围绕同一组概念:代表 GPU 的设备、描述各阶段配置的管线状态、承载数据的资源及其视图。GEA 把 API 分成高层(OpenGL、D3D11 及更早)和底层(D3D12、Vulkan、Metal、PlayStation 的 Gnm),并介绍 D3D11 的特性级别、设备上下文与延迟上下文、D3D12 的命令列表、PSO 和根签名。本页按 GEA 的整理讲这些跨 API 的共同概念,不是任何一个 API 的教程。

高层 API 与底层 API(卷 II 11.4.4)

CPU 与 GPU 的接口非常复杂:GPU 本身复杂;GPU 和显存在插在 PCIe 插槽上的扩展卡上,数据要先由 CPU 写进主内存再经 PCIe 上传;CPU 与 GPU 是独立处理器需要同步;GPU 内部大量并发的着色器调用有时也要用无锁原子操作同步。

高层 API底层 API
例子OpenGL、DirectX 11 及更早DirectX 12、Vulkan、Metal、PS4/PS5 的 Gnm
目标易用:程序员只管准备数据、配置管线、提交几何最大运行时性能,暴露硬件的全部能力
并发和显存API 在底层替你处理程序员自己负责并发与内存管理
问题不够灵活(几乎无法控制显存管理);简单的逻辑模型隐藏了硬件细节,实现中常有难以消除的低效难用得多

原书问题(11.4、11.4.4):

  • GEA 说 CPU 与 GPU"需要用互斥锁 (mutex) 同步"。CPU 与 GPU 之间不能用 mutex(GPU 不参与操作系统的锁),实际用的是 fence(围栏,GPU 执行到某处时写入一个值,CPU 等待或轮询)和 semaphore(队列之间),如 D3D12 的 ID3D12Fence::Signal/SetEventOnCompletion、Vulkan 的 VkFence/VkSemaphore(MS Learn "Synchronization and Multi-Engine";Vulkan 规范第 7 章 "Synchronization and Cache Control")。
  • GEA 说"任何图形 API 都能配置、控制、编程市场上任何 GPU"。实际受平台限制:Metal 只在 Apple 平台、Direct3D 只在 Windows/Xbox、PlayStation 只用索尼自己的 API,Vulkan 也不能用于 PlayStation 和 Apple(后者需借助 MoltenVK 翻译层)。
  • GEA 说"多数图形 API 都提供参考实现"。Direct3D 确实有参考光栅器(REF)和 WARP;但 OpenGL 和 Vulkan 没有官方参考实现,Khronos 靠一致性测试集 (CTS) 而非参考实现来检验驱动(Khronos "Vulkan Conformance Test Suite")。

GEA 第 11 章主要讲高层 API 的工作方式,只在必要处点出底层 API 的差别。对照 可编程着色器与 GPU 管线 中 RTR4 的「低开销 API」一节。

特性级别(卷 II 11.4.5.3)

  • 早期靠查询 caps 位适配硬件,组合繁多、易出兼容性 bug。DirectX 11 引入特性级别 (feature level),把硬件特性集与 DirectX 版本归成一条线性序列:GPU 支持某级别,就保证具备该级别所有必需能力;每一级都是前一级的严格超集。
  • 初始化时先尝试按最高期望级别创建 Direct3D 设备,成功即说明 GPU 支持该级别全部特性,失败就降一级重试。
  • GEA 表 11.2 的部分内容("可选"表示该级别下为可选特性):
特性引入或可选成为必需
几何着色器、流输出—10_0
外壳/域着色器与硬件细分器—11_0
计算着色器10_0 起可选11_0
BC4/BC5 纹理压缩—10_0
BC6H/BC7 纹理压缩—11_0
多渲染目标 (MRT)11_0 可选11_1
保守光栅化11_1 引入12_1
光栅顺序视图 (ROV)11_1 起可选12_1
网格着色器管线11_0 起可选12_2
硬件光线追踪11_0 起可选12_2(Tier 1.1)
可变着色率 (VRS)11_0 起可选12_2(Tier 2)
  • 着色器模型:9_x 为 2.0,10_0 为 4.0,10_1 为 4.x,11_0 到 12_1 为 5.1,12_2 为 6.5(同表)。
  • 可变着色率让程序员控制图像不同区域的像素着色器调用频率,把资源多分给细节丰富的区域、少分给细节少的区域,以性能换画质或反之。

(表中 MRT 一行按 GEA 表 11.2 原样整理,书中正文说 MRT 用于输出 G-buffer,见 像素着色器。)

原书问题(表 11.2、11.4.5.3):

  • MRT:表 11.2 写 MRT 在 10_x 及以下"不支持"、11_0 可选、11_1 起必需,与微软文档不符。同时绑定的渲染目标数是 9_1/9_2 为 1、9_3 为 4、10_0 起为 8(MS Learn "Direct3D feature levels" 特性表 "Simultaneous Render Targets" 一行);也就是说 MRT 从 9_3 起就有,10_0 起支持 8 个。
  • 根签名:GEA 说"直到 11_0 资源都直接绑定到着色器阶段,根签名提供无绑定模型,通过一张叫根签名的全局描述符表把描述符交给着色器"。根签名是 D3D12 API 的对象(D3D12 设备最低就是 11_0 级别),它不是描述符表本身,而像一个"函数签名":定义着色器期望的根参数布局(根常量、根描述符、指向描述符堆的描述符表),"并不定义实际的内存或数据";描述符本身存放在描述符堆中(MS Learn "Root Signatures Overview")。真正"着色器可按索引访问堆中任意资源"的无绑定写法是 Shader Model 6.6 的 ResourceDescriptorHeap[](MS Learn / DirectX-Specs "HLSL Dynamic Resources")。下文"根签名与无绑定"一节按 GEA 原意记录,读时以此为准。
  • 表中"Variable Shading Rate (VSR)"在 D3D 中的正式名称是 Variable Rate Shading (VRS)。

设备(卷 II 11.4.7)

API 通过逻辑软件接口暴露物理 GPU(或纯软件参考实现):

API逻辑设备物理设备信息
DirectX(基于 COM,类名多以 I 开头表示接口)D3D11 ID3D11Device、D3D12 ID3D12Device;可初始化为硬件设备、参考设备或 WARP(软件光栅器,用于无 GPU 平台或开发时模拟 GPU)DXGI 的 IDXGIAdapter(D3D11)/ IDXGIAdapter1(D3D12)
OpenGL(C 风格)不暴露逻辑设备概念,初始化后直接调用函数,可把整个 API 看作"逻辑设备"glGetString 查询
Vulkan(C 风格)VkDevice 句柄VkPhysicalDevice,配合 vkGetPhysicalDeviceProperties、vkGetPhysicalDeviceFeatures 等

逻辑设备负责创建缓冲、纹理、状态对象和着色器等资源。

管线状态与上下文(卷 II 11.4.8)

下图对比三种暴露管线状态的方式。

flowchart LR
    subgraph G["全局状态"]
        GL["OpenGL: 全局变量"] 
        IC["D3D11 立即上下文: 单例"]
    end
    DC["D3D11 延迟上下文: 多线程录制命令"] -->|"只能经立即上下文提交"| IC
    subgraph C["命令列表为中心"]
        CL["D3D12 / Vulkan / Metal: 直接构建并提交命令列表"]
    end
    IC --> GPU["GPU 按序执行命令"]
    GL --> GPU
    CL --> GPU
  • 全局状态:OpenGL 把状态当全局变量;D3D11 用 ID3D11DeviceContext,但立即上下文是单例,状态同样全局。底层都是在 CPU 端构建命令列表交给 GPU 按序执行。
  • 延迟上下文:D3D11 可创建多个,只把命令录进内存,必须通过立即上下文提交;只有一个线程能使用立即上下文,其他线程可并发使用延迟上下文。
  • 命令列表为中心:D3D12、Vulkan、Metal 没有设备上下文,一切都是构建并提交命令列表,引擎可以自由设计多线程结构(见 多线程渲染与任务系统)。
  • 旧 API 状态切换为什么贵、PSO 如何解决,见 绘制调用与状态切换优化 中的 GEA 部分。

资源与资源视图(卷 II 11.4.9)

  • DirectX 把数据块统一称为资源;OpenGL 按类型分为各种缓冲对象(纹理对象、帧缓冲对象、通用缓冲对象等);Vulkan 分为原始数据的 buffer 和位图数据的 image。D3D11 的流程:用设备创建资源 → 填数据 → 经设备上下文以资源视图绑定到一个或多个阶段 → 提交 draw call,管线读写视图 → 用完调用资源的 Release 释放。
  • 缓冲是连续内存:顶点缓冲(可由 CreateInputLayout 从多个缓冲拼出顶点结构)、索引缓冲(16 或 32 位整数,三个一组成三角形、两个一组成线段)、常量缓冲(一次 draw call 内所有调用不变的数据,如变换和投影矩阵,可看作只含一个顶点的顶点缓冲)。
  • 纹理是特殊的缓冲,可为 1D、2D、3D,可带 mipmap;D3D11 用 ID3D11Texture2D 等按维度区分的接口,D3D12 统一为带纹理配置的 ID3D12Resource,Vulkan 叫 image(VkImage)。还可建纹理数组:1D 纹理数组看似 2D 纹理,但 GPU 不会在数组元素之间插值;六元素 2D 纹理数组可作立方体贴图。
  • 有类型与无类型:有类型资源创建时就给出数据类型和布局,驱动可预先配置,效率略高;无类型资源绑定时才给出,便于在不同场合复用。
  • 资源视图:资源从不直接绑定到阶段,而是通过视图——描述如何从资源中取数据、如何解释(例如把 32 位数组解释为 RGBA 颜色),还能把资源的多个切片拼成一个连续缓冲。为同一资源建多个视图就能绑定到多个阶段,例如一个阶段当浮点数组读、另一个当无符号整数读。
视图用途
RTV 渲染目标视图把纹理当渲染目标(颜色平面或 G-buffer)
DSV 深度/模板视图把纹理当深度/模板平面
CBV 常量缓冲视图跨多次调用不变的数据,如变换矩阵
VBV / IBV绑定顶点缓冲(含属性布局)/ 索引缓冲
SRV 着色器资源视图对大块缓冲或纹理只读访问
UAV 无序访问视图着色器随机读写缓冲或纹理
ROV 光栅顺序视图类似 UAV,但按三角形提交顺序调用绑定它的像素着色器,让 OIT 可靠工作,有性能代价(见 透明渲染与 Alpha 混合)
纹理采样器严格说不是视图,但控制采样方式:寻址模式、clamp 的边框颜色、过滤模式、LOD 偏移

缓冲可绑定为 CBV、SRV、UAV、IBV、VBV;纹理只能绑定为 SRV、UAV、DSV、RTV。

原书问题(11.4.9):

  • GEA 说 Metal 中纹理"叫 layer,用 CAMetalLayer 表示"。Metal 的纹理类型是 MTLTexture(由 MTLDevice 按 MTLTextureDescriptor 创建);CAMetalLayer 是 Core Animation 的图层,用来向屏幕提供可绘制对象 (CAMetalDrawable),相当于交换链,不是纹理(Apple Developer Documentation "MTLTexture"、"CAMetalLayer")。
  • GEA 说 IBV"把索引缓冲绑定到顶点着色器"、VBV 绑定到顶点着色器并"描述顶点结构中属性的内部布局"。顶点缓冲和索引缓冲都绑定到输入装配器(D3D11 的 IASetVertexBuffers/IASetIndexBuffer,D3D12 的 IASetVertexBuffers/IASetIndexBuffer),顶点着色器看不到索引;D3D12 的 D3D12_VERTEX_BUFFER_VIEW 只含地址、大小和步长,属性布局由输入布局(D3D12_INPUT_LAYOUT_DESC,属于 PSO)描述(MS Learn "Input-Assembler Stage"、"D3D12_VERTEX_BUFFER_VIEW structure")。另外 CBV/VBV/IBV 是 D3D12 的术语,D3D11 中常量、顶点、索引缓冲是直接绑定的,没有对应的视图对象。
  • ROV 并不改变像素着色器的调用顺序;它保证的是不同图元对同一像素位置的 ROV 读写按图元提交顺序发生,着色器其余部分仍可并行乱序执行(MS Learn "Rasterizer Order Views")。
  • "带 mipmap 的二维纹理尺寸限制为 2 的幂"与 D3D10 起支持任意尺寸 mipmap 纹理的规范不符,见 纹理映射管线 中的 GEA 部分。

根签名与无绑定(卷 II 11.4.9.3)

  • D3D12 中资源视图不再直接绑定到管线阶段,着色器可以读写任意数量的视图。为此引入资源描述符——类似指向视图的指针或引用,放在着色器可直接访问的全局描述符表中。GEA 把这张全局表称为根签名 (root signature)(这一称呼不准确:全局表是描述符堆,根签名只描述布局,见上方原书问题)。
  • 在特性级别 11_0 之前资源直接绑定到着色器阶段;根签名提供所谓无绑定资源模型,所有着色器都能访问所有资源(卷 II 11.4.5.3)。对照 纹理映射管线 中 RTR4 介绍的无绑定纹理。

取舍

  • 高层 API 上手快,适合原型和教学,但显存管理和多线程受限,状态切换代价高;底层 API 能榨出硬件性能、允许多线程构建命令,但并发与内存管理全部由程序员负责(卷 II 11.4.4)。
  • 特性级别让兼容性判断变成"能否按某级别创建设备",比逐个检查 caps 位简单得多;不过表 11.2 中仍有大量"可选"项,说明特性级别只规定了必需能力的下限,并不能描述所有硬件差异。
  1. Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
  2. Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 11 章 11.4.4–11.4.5、11.4.7–11.4.9 节

相关页面

图形学可编程着色器与 GPU 管线Programmable Shaders & GPU PipelineGPU 把第 2 章的概念管线实现为一组硬件阶段,分为完全可编程、可配置但不可编程、完全固定三类。现代 GPU 采用统一着色器架构:各类着色器共用同一套编程模型和核心,由 GPU 自行分配负载。着色器用 HLSL、GLSL 等类 C 语言编写,输入分为 uniform 和 varying 两类。图形学绘制调用与状态切换优化Draw Calls & State Change Optimization调用图形 API 的开销主要在 CPU 端的驱动里:状态切换昂贵,每次绘制调用有固定开销,大量小批次会让 GPU"饿死"。对策是:合理放置缓冲;按状态代价排序分组;共享纹理和着色器;合并网格和实例化以减少调用;并用一个整数排序键同时兼顾状态分组与前后排序。游戏开发多线程渲染与任务系统Multithreaded Rendering & Task SystemsCPU 时钟频率约在 2003 年停在 3.4 GHz 附近后,性能来自多核。应用阶段的优化一是让代码与内存访问更缓存友好,二是利用多核:多处理器流水线(时间并行,提高吞吐但增加延迟)、并行处理(空间并行,延迟更低)以及两者结合的任务系统;图形 API 用命令缓冲让多个线程并行录制绘制命令,新一代 API(DirectX 12、Vulkan、Metal)把更多责任交给应用以降低驱动开销。图形学图形栈与渲染引擎架构Graphics Stack & Rendering Engine Architecture渲染引擎要解决的"渲染问题"是:给定由场景元素、虚拟光源和虚拟相机组成的虚拟世界,生成相机看到的二维彩色图像。GEA 把它拆成可见性问题和光照问题,按解法把引擎分为光线追踪、深度缓冲光栅化、辐射度和混合四类;光栅化引擎通常采用立即模式的两层结构:下层是图形管线,上层是负责剔除、提交几何和设置着色器参数的应用层。本页讲这套整体架构,管线内部见 渲染管线。图形学网格着色器管线Mesh Shader Pipeline网格着色器管线(也叫网格几何管线)是 GPU 厂商为取代传统光栅管线前段而推出的新架构:光栅化器和像素着色器不变,网格着色器和可选的放大着色器(任务着色器)接管顶点、外壳、域和几何着色器的全部工作。它以类似计算着色器的线程组处理叫 meshlet 的小批图元,像启动计算着色器一样启动绘制,还能把部分应用层工作搬到 GPU 上。2019 年进入 DirectX 12,2022 年以 VKEXTmeshshader 扩展进入 Vulkan。图形学硬件光线追踪管线Hardware Ray Tracing Pipeline高端 GPU 提供硬件加速的光线追踪,它像 GPU 中独立于光栅管线和计算管线的另一条管线,但能与它们协调同步。场景几何要先组织成两层加速结构(TLAS 实例层与 BLAS 几何层),光线发射后由 any-hit、closest-hit、miss 等着色器处理结果。由于还不够快,GPU 光追通常与光栅化结合成混合渲染:先光栅化 G-buffer,再对镜面、反射和间接光发射光线。图形学纹理压缩Texture Compression固定码率纹理压缩由 GPU 实时解码:减少显存占用、增大有效缓存、降低访问带宽,也能在同样内存下用更大纹理。BC (DXTC) 系列是桌面标准,ETC/EAC、PVRTC、ASTC 用于移动平台。它们都是有损的,压缩慢、解压快;法线贴图需要专门处理。图形学像素着色器Pixel Shader像素着色器(OpenGL 里叫片元着色器)对光栅化产生的每个片元运行,用插值后的顶点数据算出颜色,也可以输出不透明度、修改深度或直接丢弃片元。多渲染目标让它一次输出多组数据,催生了延迟着色。它通常只能写自己所在的像素,但能通过 2×2 quad 拿到相邻像素的导数。游戏开发 · UE5UE5 渲染架构UE5 Rendering ArchitectureUE5 的渲染器是独立的 Renderer 模块,在渲染线程 (Rendering Thread) 上以「场景代理」镜像游戏线程的组件状态,每帧按固定顺序执行深度预通道、G-buffer 基础通道、光照、雾、半透明和后处理。现代渲染代码用渲染依赖图 (Render Dependency Graph, RDG) 声明通道与资源,由 RDG 自动排屏障、复用瞬态内存、并行录制;最终命令经 RHI 线程翻译成 D3D12/Vulkan 等图形 API 调用。默认走延迟着色 (Deferred Shading),也可切换前向着色 (Forward Shading)。图形学纹理映射管线Texturing Pipeline纹理通过修改着色方程中使用的值(颜色、粗糙度、法线等)来高效表现表面材质的变化。通用纹理管线是:空间位置 → 投影函数得到纹理坐标 → 对应函数变换到纹理空间 → 取值 → 值变换 → 用于着色。本页还整理纹理坐标约定、纹理表示方式、程序纹理、纹理动画、材质贴图、alpha 贴图和纹理光源。图形学透明渲染与 Alpha 混合Transparency & Alpha Blending本页讲最简单的"视角相关"透明:半透明物体只衰减其后方物体的颜色。z-buffer 每像素只存一个表面,所以透明物体通常要从后往前用 over 运算符混合;顺序无关透明 (OIT) 方法用多遍渲染、逐像素链表或近似公式避免排序,各有内存、性能或准确性代价。预乘 alpha 让过滤、混合和合成更正确高效。

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原