06-rasterization-and-setup
第 6 篇:三角形设置与光栅化(Triangle Rasterization and Setup)
原文:Part 6
一句话定位
现代硬件光栅化通常把三角形转成可增量计算的边函数,再分层遍历 tile/像素块,产出覆盖掩码;它不在同一个“大循环”里顺便完成着色和纹理采样。
边函数
对每条有向边可建立形如 E(x, y) = A·x + B·y + C 的线性函数。采样点位于三角形内外,可由三个边函数的符号判断。因为从一个像素移动到相邻像素只需给 E 加固定增量,这种表示非常适合并行硬件和定点实现。
三角形设置阶段预先计算:
- 各边方程及增量;
- 包围盒、面积和面朝向;
- 用于属性/深度插值的平面参数;
- 与填充规则、采样位置相关的偏置。
设置成本几乎按三角形计,而不是按覆盖像素计。这解释了为什么大量亚像素三角形会让前端/设置单元成为瓶颈。
粗到细的分块遍历
flowchart TD
T[屏幕空间三角形] --> B[计算包围盒与边方程]
B --> C[Coarse Raster<br/>测试较大 tile]
C -->|完全在外| X[丢弃 tile]
C -->|相交/在内| F[Fine Raster<br/>测试小块/采样点]
F --> M[coverage mask]
大块测试能一次拒绝许多像素,细阶段再生成精确覆盖。层次遍历兼顾大三角形吞吐与局部数据组织,也方便与 hierarchical Z、ROP 分区和内存 tile 对齐。
填充规则与水密性
两个三角形共享一条边时,采样点不能被双方都排除形成裂缝,也不应被双方重复覆盖。Top-left 一类规则通过对“恰好落在边上”的样本做确定性归属,保证拼接图元的一致覆盖。
实现常用定点或严格受控的舍入,原因不是 GPU 不会浮点,而是覆盖判定必须在所有相关单元中可复现。几何中的 T-junction 则没有真正共享同一条边,有限精度下更容易产生裂缝,应在模型/细分阶段修复。
小三角形与细长三角形
- 小三角形可能只贡献 0~1 个像素,却仍支付完整的装配、设置和至少一次 tile 测试成本。
- 细长三角形可能跨过大量 tile,但每个 tile 只覆盖极少像素,粗阶段效率很差。
- 优化不能只看总三角形数,还要看屏幕空间大小、形状、分布,以及每个 primitive 产生的有效像素数。
术语对照
| 英文 | 中文理解 | 作用 |
|---|---|---|
| triangle setup | 三角形设置 | 预计算边/插值方程等常量 |
| edge function | 边函数 | 判定采样点相对边的位置 |
| coarse rasterization | 粗光栅化 | 以 tile 为粒度筛选 |
| fine rasterization | 细光栅化 | 生成像素/样本覆盖掩码 |
| coverage mask | 覆盖掩码 | 指明哪些 sample 被图元覆盖 |
| top-left rule | 左上填充规则 | 处理恰落在共享边上的样本 |
| sliver triangle | 细长三角形 | 跨 tile 多、有效覆盖低 |
面向 UMD/KMD 的阅读提示
- UMD 配置 polygon mode、cull、front face、sample count、sample locations、conservative raster 等状态。
- 某些“看似 shader 的输出”会影响固定功能设置,例如 clip/cull distance、layer、viewport index。
- 调优时结合 primitive、clipped primitive、rasterized tile、PS invocation 等 counter,判断瓶颈在设置、粗光栅还是像素端。
- 这部分几乎都在硬件数据面;KMD 的职责主要是保证命令和资源可执行,不参与逐三角形判断。
自测与实验
- 保持总屏幕覆盖面积近似相同,把网格不断细分,观察何时从像素瓶颈转为前端瓶颈。
- 为什么用包围盒逐像素测试虽正确,却不一定有高吞吐?
- MSAA 增加的是 coverage sample,为什么不一定按相同比例增加 pixel shader invocation?
本篇总结
光栅化硬件的核心是“把几何转成规则、局部、可批量判断的覆盖问题”;边函数和分块层次是实现这一点的关键。

浙公网安备 33010602011771号