一:DX12 相较于 OpenGL 之类的旧 API 有什么优势#
核心优势:更底层、更显式、更加适配多线程与现代 GPU 架构。DX12 将旧 API 中许多底层工作交还给应用层,从而使得引擎能够自己控制资源、同步以及命令提交,减少了驱动带来的开销,也提升了程序的可预测性。
CPU 开销更低:
- 在 OpenGL / DX11 中,诸如资源同步、内存管理、命令验证等操作都是由驱动自己完成的,而在 DX12 中需要自己手动地进行显式管理,比如 CPU 与 GPU 的 Fence 设置、使用 Descriptor Heap 绑定描述符、通过 Command List 录制命令等。
- 这样使得驱动需要去猜的东西变少了,CPU 端的成本更加可控。
多线程的命令录制更好:
- OpenGL / DX11 的命令录制很容易集中在一个主线程上,DX12 支持同时利用多个线程进行命令录制,因此引擎可以将阴影 Pass、后处理、场景遍历等分配给多个线程生成 GPU 命令,降低 CPU 主线程的处理压力。
资源与内存控制更加显式:
- DX12 允许程序员对资源生命周期、堆内存分配等手动进行管理,而旧 API 都是由驱动自动进行管理。
状态切换更加高效:
- DX11 / OpenGL 都是传统的状态机模型,状态多、变化频繁,因此驱动需要不断地去进行验证;DX12 使用的是 PSO(Pipeline State Object),将大量管道状态预先打包,之后在运行期中只需要对创建好的 PSO 进行绑定即可,减少了运行期的状态切换与验证成本。
同步更加可控:
- 在旧 API 中,许多同步操作是隐式的,所以可能会出现“上一帧使用某个资源,下一帧又需要对其进行写入,于是驱动偷偷插入等待、重命名等操作来避免冲突”的情况。
- DX12 的同步更加显式:
- CPU / GPU 用 Fence。
- GPU 内部资源状态用 ResourceBarrier。
- 多 Queue 之间也要显式同步。
补充:缺点是现代 API 的代价是复杂度更高,DX12 把原本由驱动完成的工作交由程序员手动完成,如果处理不当,DX12 可能会比 DX11 等旧 API 还要慢。
二:DX12 是如何将一帧绘制到屏幕上的#
获取当前的 Back Buffer:
- Swap Chain 中包含多个缓冲区,当前帧需要绘制到其中一个 Back Buffer 上。
CPU 录制命令:
- CPU 先重置 Command Allocator 和 Command List,再将绘制操作逐个录制。
资源状态切换:
- Back Buffer 初始通常处于 PRESENT 状态,需要使用 Resource Barrier 将其切换至 RENDER_TARGET 状态,这样 GPU 才能往里面写入颜色。
设置渲染目标:
- 为当前的 Back Buffer 绑定 RTV,如果需要深度测试,还要绑定 DSV。
清屏:
- 将当前颜色缓冲区与深度缓冲区清空。
设置渲染管线:
- 对 PSO、Root Signature、顶点缓冲 / 索引缓冲、常量缓冲、纹理、采样器、Viewport 等进行绑定。
发出 Draw Call:
- 之后 GPU 会经过顶点着色、光栅化、像素着色等操作,将结果写入 Back Buffer。
资源状态切换:
- 将 Back Buffer 从 RENDER_TARGET 切回 PRESENT,准备交给显示系统。
提交命令至 GPU:
- CPU 关闭 Command List,通过 Command Queue 将命令提交至 GPU 进行执行。
显示:
- 调用
SwapChain->Present(...),DXGI 会将渲染好的 Back Buffer 交给显示系统,最终显示在屏幕上。
- 调用
Fence 同步:
- CPU 通过 Fence 确认 GPU 已经绘制完成这一帧,此时才可以复用这一帧的 Back Buffer。
三:Command Queue 的三种类型#
DX12 将 GPU 工作拆成不同队列,方便图形、计算、拷贝异步执行,但队列之间仍需显式同步
支持所有 GPU 操作,如 Draw(绘制)、Compute(计算)、Copy(资源转移)、Resource Barrier(资源状态转换)等
主要支持 Compute Shader 指令和资源复制/转移操作,通常不支持绘制等图形相关指令(如光栅化);适用于物理模拟、GPU 粒子系统等
原笔记(优先级表述待复核)
仅支持拷贝、填充、清空等简单的内存操作,用于主机到显存的资源上传、显存内的数据移动等
来源:语雀原笔记