07-depth-stencil

第 7 篇:深度/模板处理的三条路径(Z/Stencil Processing)

原文:Part 7

一句话定位

深度/模板测试既可以在像素着色前尽早拒绝工作,也可能必须在着色后按精确结果更新;硬件用 Early Z、Late Z 与层次测试平衡正确性和效率。

深度插值

经过投影与视口变换后,深度可以在屏幕空间按平面方程增量计算。其他属性通常需要透视正确插值:可以理解为先对与 1/w 相关的量做线性插值,再恢复正确属性,或使用透视正确的重心坐标。

三个层级

flowchart LR A[光栅化 tile/quad] --> H[Hierarchical Z/Stencil<br/>保守地整块拒绝] H --> E[Early Z/Stencil<br/>逐样本测试] E --> P[Pixel Shader] P --> L[Late Z/Stencil<br/>最终测试/更新] L --> O[颜色与深度输出]

Early Z

当 shader 不会改变深度,也不会以影响可见性的方式 kill sample 时,着色前测试能避免大量无用 shader 工作。即使某些情况不能提前写深度,也可能安全地做保守的提前拒绝。

为什么需要 Late Z

以下行为会限制提前测试或提前写入:

  • shader 写自定义深度;
  • discard/alpha test/alpha-to-coverage 等可能删除片段或样本;
  • shader 副作用与 API 的 early-test 语义相互作用;
  • 顺序和同步要求不能通过保守判断满足。

API 或 shader 装饰可显式要求 early tests,但程序必须接受相应语义:例如某些副作用可能在最终片段未产生颜色时已经发生。

Hierarchical Z/Stencil

层次结构为 tile 保存保守摘要,例如一块区域的深度范围。若新三角形的整块深度肯定无法通过,就无需进入逐像素测试。摘要允许假阴性效率损失(没能拒绝),但不能错误拒绝本应通过的样本。

顺序与写入位置

Early 和 Late 阶段若都能写同一深度缓冲,会产生先后批次交叠和竞争风险。真实实现需要集中排序/提交写入、保守延迟写、flush,或使用其他机制保证 API 顺序。性能上“开启深度测试”不是单一开关,而是 shader 行为、深度写、比较函数与批次切换共同决定的路径。

深度压缩与快速清除

深度具有强空间局部性,tile 内值常可用基值/差值或其他元数据压缩,减少带宽。快速清除可只更新元数据,把“整个表面是某个清除值”延迟物化;后续读者若不能理解该压缩状态,就必须先 resolve/decompress。

术语对照

英文 中文理解 关键约束
Early Z 提前深度测试 尽早拒绝,必须保持结果等价
Late Z 延后深度测试 可使用 shader 最终深度/存活信息
Hierarchical Z 层次深度 tile 级保守拒绝
depth write 深度写入 与测试、顺序和压缩状态耦合
conservative test 保守测试 可漏掉优化机会,不可误杀可见样本
fast clear 快速清除 用元数据表示统一清除值

面向 UMD/KMD 的阅读提示

  • 编译器分析 shader 是否写 depth、使用 discard、产生存储副作用,并选择 early/late 相关控制位。
  • 状态跟踪要知道 depth attachment 的布局、压缩和 clear 元数据;切换用途时可能插入 decompress/resolve/barrier。
  • render pass 合并与 tile-based GPU 的 attachment load/store 策略,会显著改变深度流量,但语义问题相同。
  • KMD 不判断 early Z 是否安全;它负责相关 BO、同步和队列执行的系统级正确性。

自测

  • 为什么 discard 可能使“提前写深度”不安全,但仍可能允许“提前拒绝”?
  • 层次 Z 为什么必须保守?元数据陈旧会导致哪两类结果?
  • 关闭深度写但保留深度测试,可能改善或恶化哪些路径?

本篇总结

深度优化的本质是在不改变可观察结果的前提下尽可能早地证明“这批样本没有贡献”,并用层次元数据把证明粒度从样本扩大到 tile。

posted @ 2026-10-26 21:58  Sailxiv  阅读(1)  评论(0)    收藏  举报