11-stream-out
第 11 篇:Stream-Out
原文:Part 11
一句话定位
Stream-Out(OpenGL 中常称 Transform Feedback)把顶点/几何阶段的输出直接写入缓冲,使流水线中间结果可被后续 draw 或 CPU/其他阶段复用。
数据路径
flowchart LR
VS[VS 输出] --> GS[可选 GS]
GS --> R[后续光栅化]
VS -.无 GS 时也可.-> SO[Stream-Out]
GS --> SO
SO --> B[内存缓冲]
B --> D[后续 Draw / 间接输入 / 读回]
在某些 API 表达中,SO 被画在 GS 之后;这不代表必须执行一个真正 GS。驱动/硬件可让 VS 输出直接进入 SO,只需满足 API 对输出布局和顺序的规定。
为什么它不只是一次普通 store
SO 要把 shader 输出属性按声明布局写入一个或多个目标缓冲,并维护当前写指针、stride、边界和统计。若 GS 输出数量可变,实际写入大小直到运行时才知道。硬件还要处理:
- 多 stream 或多 buffer 的分配;
- primitive 完整性,避免空间不足时写出半个图元;
- overflow 检测与查询统计;
- 与光栅化并行消费同一输出时的扇出;
- 后续把结果作为 vertex/index/indirect 数据读取时的可见性。
常见用途
- 缓存蒙皮或其他昂贵顶点变换结果;
- 粒子更新与几何反馈;
- 捕获流水线中间数据用于调试;
- 在早期 API/硬件上承担部分通用计算任务。
现代 compute 往往更灵活,但 SO 的顺序化输出和与图形流水线的直接连接仍有价值。
计数与间接执行
当输出数量由运行时决定,CPU 若先读回计数再发下一次 draw,会引入 GPU→CPU 同步停顿。更理想的路径是让 GPU 维护计数,并由后续间接 draw/dispatch 直接消费。读代码时要区分“数据缓冲”“写入计数/查询”“间接参数”是否为同一对象,以及它们之间插入何种 barrier。
术语对照
| 英文 | 中文理解 | 说明 |
|---|---|---|
| Stream-Out | 流输出 | D3D 术语 |
| Transform Feedback | 变换反馈 | OpenGL 近似对应概念 |
| stream | 输出流 | GS 可将图元导向不同流 |
| stride | 步长 | 相邻输出记录间的字节距离 |
| append counter | 追加计数器 | 指示下一写入位置/输出数量 |
| overflow | 溢出 | 目标容量不足,需按 API 规则处理 |
面向 UMD/KMD 的阅读提示
- 找 SO declaration 如何从 shader 输出 location/component 映射到 buffer offset。
- 追踪 buffer 既作 SO target 又作 vertex source 时的 cache flush 与 hazard tracking。
- 查询结果通常是异步写入;CPU 读取前需要等待,GPU 间接消费则可能只需设备侧 barrier。
- KMD 负责 BO 与同步生命周期,不负责字段如何打包;字段布局属于 UMD/硬件 ABI。
自测与实验
- 为什么输出缓冲剩余空间不足一个完整 primitive 时,不能简单写到末尾为止?
- 用 CPU 读取 SO 计数再 draw,与 GPU indirect draw 相比,流水线停顿在哪里?
- 若同一 pass 同时光栅化并 stream-out,输出扇出会增加哪些带宽和缓冲压力?
本篇总结
Stream-Out 将“流水线内部记录”变成“有布局、有计数、有同步语义的内存数据”,是理解 GPU 生产者—消费者链路的好例子。

浙公网安备 33010602011771号