输入装配器 (IA) 通过将源几何图形数据从 1D 缓冲区中拉取,将三角形、线条或点引入渲染管道。
顶点数据可以来自多个缓冲区,并且可以从每个缓冲区以结构数组的方式访问。 每个缓冲区都绑定到单个输入槽,并给定一个结构步幅。 跨所有缓冲区的数据布局由输入声明指定,其中每个条目定义一个 元素。 元素包含管道) 中第一个活动着色器的输入槽、结构偏移量、数据类型和目标寄存器 (。
给定的顶点序列是从缓冲区提取的数据构造的。 数据在固定函数状态和各种 Draw* () DDI 调用的组合定向的遍历中获取。 各种基元拓扑 (例如点列表、行列表、三角形列表和三角形带) 可用于使顶点数据序列表示基元序列。
可以通过以下两种方式之一生成顶点数据。 生成顶点数据的第一种方法是 非索引 呈现,这是包含顶点数据的缓冲区的顺序遍历。 顶点数据源自每个缓冲区绑定的起始偏移量。 生成顶点数据的第二种方法是 索引 呈现,这是包含标量整数索引的单个缓冲区的顺序遍历。 索引源自缓冲区的起始偏移量。 每个索引指示从包含顶点数据的缓冲区中提取数据的位置。 索引值与它们引用的缓冲区的特征无关。 缓冲区由声明描述。 非索引和索引呈现,每个呈现都以自己的方式生成地址,从中获取内存中的顶点数据,然后将结果组合到顶点和基元中。
通过允许在非索引呈现或索引呈现中,顺序遍历在每个顶点缓冲区内循环, (非索引大小写) 或索引缓冲区 (索引大小写) 来启用实例化几何图形呈现。 可以将缓冲区绑定标识为 实例数据 或 顶点数据。 此标识指定在执行实例化呈现时如何使用绑定缓冲区。 非索引或索引呈现生成的地址用于提取顶点数据,这也考虑了运行时执行实例化呈现时的循环。 另一方面,始终从每个缓冲区偏移量开始按顺序遍历实例数据,其频率等于每个实例一个步骤 (例如,在) 遍历实例中的顶点数后向前一步。 实例数据的步进速率也可以选择为实例频率 (的子调和,即,每个其他实例向前一步,每三个实例) ,依此类推。
IA 的另一个特殊情况是,它可以读取流输出阶段写入的缓冲区。 此类方案启用一种新型的绘制操作 DrawAuto。 DrawAuto 允许在不涉及 CPU 的情况下重复使用写入流输出缓冲区的动态输出量,以确定实际写入的数据量。
除了从缓冲区生成顶点数据外,IA 还可以自动生成三个标量计数器值:VertexID、PrimitiveID 和 InstanceID,以便输入到呈现管道中的着色器阶段。
在带状拓扑(如三角形带)的索引呈现中,提供了一种机制,用于使用单个 *Draw* () 调用 (绘制多个条带,即) 剪切条带的 *cut 命令。
1. 核心功能概述
输入装配器 (Input Assembler, IA) 是渲染管线的首个固定功能阶段,负责将原始几何数据(顶点、索引)组装成图元(点、线、三角形)。其核心任务包括:
- 数据提取:从1D缓冲区读取顶点/索引数据。
- 拓扑解释:将数据转换为指定图元类型(如三角形列表、线带)。
- 实例化支持:高效处理重复几何体(如批量渲染相同模型)。
- ID生成:自动生成 VertexID、PrimitiveID、InstanceID 供着色器使用。
2. 数据输入机制
(1) 数据来源
数据源 | 描述 |
---|---|
顶点缓冲区 | 存储顶点属性(位置、法线、UV等),支持多缓冲区绑定。 |
索引缓冲区 | 存储顶点索引,支持16/32位整数,优化顶点复用。 |
流输出缓冲区 | 从几何着色器 (GS) 输出的数据可循环回IA(通过 DrawAuto )。 |
(2) 数据组织方式
结构数组 (Struct-of-Arrays)
每个缓冲区绑定到独立输入槽,数据按跨步(Stride)访问:
// 示例:顶点缓冲区布局(位置 + 法线)
struct Vertex { float3 Pos; float3 Normal; };
D3D10DDI_HRESOURCE hBuffer;
UINT stride = sizeof(Vertex); // 步幅为24字节
UINT offset = 0;
pDeviceFuncs->IaSetVertexBuffers(hDevice, 0, 1, &hBuffer, &stride, &offset);
输入槽声明
通过 CreateElementLayout 定义如何组合多缓冲区的数据:
D3D10DDI_ELEMENT_LAYOUT_DESC elements[] = {
{ 0, 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10DDI_INPUT_PER_VERTEX }, // 位置
{ 0, 12, DXGI_FORMAT_R32G32B32_FLOAT, 1, D3D10DDI_INPUT_PER_VERTEX } // 法线
};
3. 图元拓扑与绘制方式
(1) 支持的拓扑类型
拓扑类型 | 描述 | 适用场景 |
---|---|---|
D3D10DDI_PRIMITIVE_POINTLIST |
独立点 | 粒子系统 |
D3D10DDI_PRIMITIVE_LINELIST |
独立线段 | 线框渲染 |
D3D10DDI_PRIMITIVE_TRIANGLELIST |
独立三角形 | 通用网格渲染 |
D3D10DDI_PRIMITIVE_TRIANGLESTRIP |
三角形带(共享顶点) | 连续表面(如地形) |
(2) 绘制调用
非索引绘制 (Draw)
直接顺序读取顶点缓冲区:
pDeviceFuncs->Draw(hDevice, vertexCount, startVertex);
索引绘制 (DrawIndexed)
通过索引缓冲区间接引用顶点:
pDeviceFuncs->DrawIndexed(hDevice, indexCount, startIndex, baseVertex);
实例化绘制 (DrawInstanced/DrawIndexedInstanced)
重复渲染相同几何体,支持逐实例数据步进:
pDeviceFuncs->DrawIndexedInstanced(hDevice, indexCountPerInstance, instanceCount,
startIndex, baseVertex, startInstance);
4. 高级特性
(1) 实例化 (Instancing)
顶点数据:每实例更新一次(如世界矩阵)。
实例步进速率:可配置为每N实例更新一次(如每2实例一个变换)
// 绑定实例数据缓冲区(步幅较大)
UINT instanceStride = sizeof(InstanceData);
pDeviceFuncs->IaSetVertexBuffers(hDevice, 1, 1, &hInstanceBuffer, &instanceStride, &offset);
(2) 流输出循环 (DrawAuto)
允许几何着色器输出数据直接作为IA输入,完全绕过CPU:
pDeviceFuncs->DrawAuto(hDevice); // 自动读取GS写入的缓冲区
(3) 自动生成ID
ID类型 | 用途 |
---|---|
SV_VertexID |
标识当前顶点(非索引绘制时为顺序号)。 |
SV_InstanceID |
标识当前实例(用于实例化区分)。 |
SV_PrimitiveID |
标识当前图元(GS/PS中可用)。 |
5. 驱动函数实现
Direct3D 运行时通过以下DDI函数控制IA:
函数 | 职责 |
---|---|
CalcPrivateElementLayoutSize |
计算输入布局私有数据大小。 |
CreateElementLayout |
创建输入布局对象(定义顶点数据结构)。 |
DestroyElementLayout |
释放输入布局资源。 |
IaSetIndexBuffer |
绑定索引缓冲区。 |
IaSetInputLayout |
设置当前输入布局。 |
IaSetTopology |
设置图元拓扑类型。 |
IaSetVertexBuffers |
绑定顶点缓冲区(支持多槽位)。 |
示例驱动实现:
// 设置顶点缓冲区
void APIENTRY IaSetVertexBuffers(
D3D10DDI_HDEVICE hDevice,
UINT StartSlot,
UINT NumBuffers,
const D3D10DDI_HRESOURCE* phBuffers,
const UINT* pStrides,
const UINT* pOffsets
) {
MyDeviceContext* pCtx = (MyDeviceContext*)hDevice.pDrvPrivate;
for (UINT i = 0; i < NumBuffers; ++i) {
pCtx->vertexBuffers[StartSlot + i] = phBuffers[i];
pCtx->strides[StartSlot + i] = pStrides[i];
pCtx->offsets[StartSlot + i] = pOffsets[i];
}
}
6. 性能优化建议
- 顶点复用:优先使用索引绘制(减少重复顶点处理)。
- 实例化:对重复对象使用 DrawInstanced 降低API开销。
- 数据对齐:确保顶点缓冲区步幅符合硬件要求(如16字节对齐)。
- 流输出缓存:复用 DrawAuto 避免CPU-GPU同步。
总结
输入装配器 (IA) 是Direct3D 10渲染管线的数据网关,其核心价值在于:
- 灵活的数据组织:支持多缓冲区、结构数组、实例化。
- 高效的图元组装:通过索引/非索引绘制适配不同场景。
- 与着色器协同:自动生成ID、支持流输出循环。