1616 字
8 分钟
DirectX 11 核心架构与基础原理

一. 编程模型:组件对象模型 (COM)#

DirectX 11 的 API 是基于 COM (Component Object Model) 标准构建的。这是理解 DX11 内存管理与接口调用的前提。

1 接口与生命周期#

  • 二进制标准:COM 是一种二进制接口标准,允许不同语言(C++, C#等)通过统一的虚函数表(vtable)调用 DirectX 驱动程序功能。
  • IUnknown 接口:所有 DirectX 资源(如 ID3D11Device, ID3D11Buffer)均继承自 IUnknown 接口。
  • 引用计数 (Reference Counting)
  • DirectX 对象不由 C++ 的 new/delete 关键字管理。
  • 生命周期控制:当通过 API(如 D3D11CreateDevice)创建对象时,内部引用计数为 1。每当该对象被赋值或绑定到新的管线阶段时,引用计数可能增加 (AddRef)。
  • 内存释放:程序员必须在不再使用对象时调用 Release() 方法。当引用计数归零时,对象自动销毁并释放显存。
  • 最佳实践:使用 Microsoft::WRL::ComPtr<T> 智能指针来自动管理 Release() 调用,防止内存泄漏。

二. 硬件抽象层:Device 与 DeviceContext#

DirectX 11 引入了多线程渲染支持,为此将传统的“渲染设备”概念解耦为两个核心接口。

1 ID3D11Device (虚拟适配器)#

该接口代表显卡硬件(Video Adapter)的虚拟化实例。

  • 核心职责资源分配 (Resource Allocation)

  • 创建资源(纹理、缓冲区)。

  • 创建视图(Views)。

  • 创建着色器对象(Shaders)。

  • 检查硬件功能等级(Feature Levels)。

  • 线程特性线程安全 (Thread-Safe)。允许多个线程同时调用 Create 系列函数创建资源,内部实现了无锁或细粒度锁机制。

2 ID3D11DeviceContext (设备上下文)#

该接口代表渲染管线的当前状态与命令列表。

  • 核心职责渲染命令发送 (Command Dispatch)

  • 绑定管线状态(Input Layout, Shaders, States)。

  • 绑定资源到槽位(Vertex Buffers, Constant Buffers)。

  • 执行绘制命令(Draw, Dispatch)。

  • 类型

  1. Immediate Context (立即上下文):直接向 GPU 驱动程序提交命令缓冲区。每个应用程序通常只有一个,非线程安全,必须在主渲染线程使用。
  2. Deferred Context (延迟上下文):将命令录制到命令列表(Command List),随后由立即上下文执行。用于多线程渲染优化。

三. 图形基础设施:DXGI 与 交换链#

DirectX Graphics Infrastructure (DXGI) 是一个独立于 Direct3D 的子系统,负责处理与底层硬件和窗口系统的交互。

1. 交换链 (Swap Chain)#

为了避免屏幕刷新时的“撕裂 (Tearing)”现象,图形渲染采用双缓冲 (Double Buffering) 或多缓冲机制。

  • Front Buffer (前台缓冲区):包含当前显示器正在扫描显示的图像数据。对 CPU/GPU 通常是只读的。
  • Back Buffer (后台缓冲区):GPU 正在进行光栅化和像素填充的目标内存。
  • Present (呈现)
  • 当一帧绘制完成,调用 IDXGISwapChain::Present
  • Flip Model:DXGI 并不拷贝像素数据,而是直接交换 Front Buffer 和 Back Buffer 的显存指针(Pointer Swap)。此操作在垂直同步(VSync)信号到来时执行,确保画面完整性。

四. 坐标系统与规范化设备坐标 (NDC)#

在光栅化发生之前,所有的几何变换最终必须输出到特定的坐标系中,以便硬件进行裁剪和映射。

1 规范化设备坐标 (NDC)#

无论场景中的单位是米还是公里,经过投影变换后,可视空间被压缩到一个标准立方体中:

  • 坐标范围

  • X[1,1]X \in [-1, 1]

  • Y[1,1]Y \in [-1, 1]

  • Z[0,1]Z \in [0, 1] (DirectX 标准,与 OpenGL 的 [-1, 1] 不同)

  • 裁剪 (Clipping):任何落在此立方体之外的顶点或图元部分,都会被硬件自动丢弃。

  • 左手坐标系 (Left-Handed):DirectX 默认使用左手系(Z 轴指向屏幕内)。

2 拓扑结构 (Primitive Topology)#

定义顶点流如何被解释为几何图形。

  • D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST:每三个顶点构成一个独立的三角形。
  • Winding Order (绕序)
  • 顺时针 (Clockwise):通常定义为三角形的正面
  • 逆时针 (Counter-Clockwise):定义为背面。
  • 背面剔除 (Backface Culling):光栅化阶段会自动丢弃背对摄像机的三角形,以节省像素着色器开销。

五. 最小化渲染管线数据流#

绘制一个最简单的图形(如三角形),数据在 CPU 与 GPU 之间的流转过程如下:

1 阶段一:输入装配 (Input Assembler, IA)#

  • 输入

  • Vertex Buffer:驻留在显存(Video Memory)中的结构化数据。

  • Input Layout:C++ 结构体与 HLSL 输入签名之间的映射描述(如 DXGI_FORMAT_R32G32B32_FLOAT 对应 float3)。

  • 操作:GPU 根据索引缓冲区(如果有)读取顶点,根据拓扑结构组装图元。

2 阶段二:顶点着色器 (Vertex Shader, VS)#

  • 输入:单个顶点的属性(Model Space)。

  • 核心逻辑

  • 对于 2D/UI 绘制:直接透传坐标(Pass-through),坐标需预先定义在 NDC 空间。

  • 对于 3D 绘制:执行 MVP 矩阵变换 (Projection×View×World×VertexProjection \times View \times World \times Vertex)。

  • 输出:齐次裁剪空间坐标 float4(x, y, z, w)

3 阶段三:光栅化 (Rasterizer Stage, RS)#

  • 硬件固定功能(不可编程)。
  • 视口变换 (Viewport Transform):将 NDC 坐标 (x,y)(x, y) 映射到屏幕像素坐标(如 019200 \to 1920)。
  • 插值 (Interpolation):计算三角形内部像素的属性(颜色、UV、法线)。使用的是重心坐标插值 (Barycentric Interpolation)

4 阶段四:像素着色器 (Pixel Shader, PS)#

  • 输入:插值后的像素属性。
  • 核心逻辑:决定像素的最终颜色。可以是简单的常量颜色,也可以是纹理采样结果。
  • 输出float4 颜色向量 (RGBA)。

5 阶段五:输出合并 (Output Merger, OM)#

  • 操作

  • 深度/模板测试 (Depth/Stencil Test):对比当前像素 Z 值与 Depth Buffer。

  • 混合 (Blending):将新计算的像素颜色与 Render Target 上已有的颜色进行混合(用于半透明)。

  • 结果:写入 Back Buffer。


六. 核心 API 签名参考#

1 初始化阶段#

// 创建设备与交换链
D3D11CreateDeviceAndSwapChain(
nullptr, // Adapter
D3D_DRIVER_TYPE_HARDWARE, // Driver Type
...,
&device, // [OUT] ID3D11Device
&context // [OUT] ID3D11DeviceContext
);

2 资源创建#

// 描述缓冲区属性
D3D11_BUFFER_DESC bd = {};
bd.Usage = D3D11_USAGE_DEFAULT; // GPU 读写,CPU 不可直接访问
bd.ByteWidth = sizeof(Vertex) * 3; // 总字节数
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; // 绑定为顶点缓冲
// 提供初始化数据
D3D11_SUBRESOURCE_DATA initData = {};
initData.pSysMem = vertices; // 系统内存指针
// 创建
device->CreateBuffer(&bd, &initData, &vertexBuffer);

3 绘制命令#

// 设置管线状态
context->IASetInputLayout(layout);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
// 设置着色器
context->VSSetShader(vertexShader, nullptr, 0);
context->PSSetShader(pixelShader, nullptr, 0);
// 执行绘制
// 3: 顶点数量, 0: 起始偏移
context->Draw(3, 0);
DirectX 11 核心架构与基础原理
https://www.m4doka.xyz/posts/dx11/dx11-1/
作者
m4doka
发布于
2026-01-12
许可协议
CC BY-NC-SA 4.0