渲染命令中着色器调用的频率

Frequency of shader invocations in rendering commands

着色器有调用,每个调用(通常)被赋予一组唯一的输入数据,并且每个(通常)写入自己单独的输出数据。当您发出渲染命令时,每个着色器会被调用多少次?

每个着色器阶段都有自己的调用频率。我将使用 OpenGL 术语,但 D3D 的工作方式相同(因为它们都模拟相同的硬件关系)。

顶点着色器

这些是第二复杂的。他们为每个输入顶点执行一次......有点。如果您使用的是非索引渲染,那么该比率正好是 1:1。每个输入顶点都将在单独的顶点着色器实例上执行。

如果您使用索引渲染,那么它会变得复杂。它或多或少 1:1,每个顶点都有自己的 VS 调用。但是,多亏了 post-T&L caching,顶点着色器的执行次数 少于 每个输入顶点一次。

看,假设顶点着色器的执行在输入顶点数据和输出顶点数据之间创建 1:1 映射。这意味着如果您将相同的输入数据传递给顶点着色器(在相同的渲染命令中),您的 VS 将生成相同的输出数据。因此,如果硬件可以检测到它即将对之前使用过的相同输入数据执行顶点着色器,它可以跳过该执行并简单地使用之前执行的输出。假设它有那些值,比如在缓存中。

硬件通过使用顶点的索引检测到这一点(这就是它不适用于非索引渲染的原因)。如果向顶点着色器提供相同的索引,则假定着色器将获得所有相同的输入值,因此将生成相同的输出值。因此硬件将根据索引缓存输出值。如果索引在 post-T&L 缓存中,则硬件将跳过 VS 的执行并仅使用输出值。

实例化只会稍微复杂化 post-T&L 缓存。它不是仅在顶点索引上缓存,而是根据索引和 instance ID 进行缓存。因此它仅在两个值相同时才使用缓存数据。

所以一般来说,VS 对每个顶点执行一次,但是如果你用索引数据优化你的几何体,它可以执行更少的次数。有时 少得多 ,这取决于你怎么做。

曲面细分控制着色器

或 D3D 术语中的外壳着色器。

TCS在这方面很简单。它将为渲染命令的每个补丁中的每个顶点恰好执行一次。这里没有缓存或其他优化。

细分评估着色器

或 D3D 术语中的域着色器。

TES 在曲面细分图元生成器生成新顶点后执行。因此,它执行的频率显然取决于您的曲面细分参数。

TES 获取曲面细分器生成的顶点并输出顶点。它以 1:1 的比例这样做。

但与顶点着色器类似,对于每个输出基元中的每个顶点,它都没有必要 1:1。与 VS 一样,TES 被假定为在细分图元和输出参数中的位置之间提供直接 1:1 映射。因此,如果您使用相同的补丁位置多次调用 TES,则预计会输出相同的值。

因此,如果生成的基元共享顶点,TES 通常只会为此类共享顶点调用一次。与顶点着色器不同,您无法控制硬件将使用它的程度。你能做的最好的事情就是希望生成算法足够聪明,以最大限度地减少它调用 TES 的频率。

几何着色器

几何着色器将为每个点、线或三角形基元调用一次,由渲染命令直接给出或由曲面细分器生成。因此,如果您将 6 个顶点渲染为未连接的线,您的 GS 将被恰好调用 3 次。

每个 GS 调用都可以生成零个或多个原语作为输出。

GS 可以在内部使用实例化(在 OpenGL 4.0 或 Direct3D 11 中)。这意味着,对于到达 GS 的每个原语,GS 将被调用 X 次,其中 X 是 GS 实例的数量。每个这样的调用都将获得相同的输入原始数据(具有用于区分此类实例的特殊输入值)。这对于更有效地将图元定向到分层帧缓冲区的不同层非常有用。

片段着色器

或 D3D 术语中的像素着色器。即使它们还不是像素,也可能不会成为像素,并且它们可以针对 相同 像素执行多次 ;)

就调用频率而言,这些是最复杂的。他们执行的频率取决于很多因素。

对于图元光栅化到的每个像素大小的区域,FS 必须至少执行一次。但他们可能会被处决更多。

为了计算纹理函数的导数,一个 FS 调用通常会从其相邻调用之一借用值。如果 没有 这样的调用,如果邻居落在被光栅化的图元边界之外,这是有问题的。

在这种情况下,仍然会有一个相邻的FS调用。即使它不产生实际数据,它仍然存在并且仍然有效。好的部分是这些帮助程序调用不会影响性能。他们基本上用完了原本不会被使用的着色器资源。此外,系统将忽略此类帮助程序调用实际输出数据的任何尝试。

但它们在技术上仍然存在。

一个不太透明的问题围绕着多重采样。看,允许多重采样实现(特别是在 OpenGL 中)自行决定要发出多少 FS 调用。虽然有一些方法可以强制多重采样渲染为每个样本创建一个 FS 调用,但没有保证在这些情况之外,实现只会对每个覆盖像素执行一次 FS。

例如,如果我没记错的话,如果您在某些 NVIDIA 硬件(8 到 16 或类似的东西)上创建具有高样本数的多样本图像,那么硬件可能会决定多次执行 FS。不一定每个样本一次,而是每 4 个样本一次。

那么你得到了多少次 FS 调用?被光栅化的图元覆盖的每个像素大小的区域至少有一个。如果您正在进行多重采样渲染,可能会更多。

计算着色器

您指定的确切调用次数。也就是说,您分派的工作组数量 * 您的 CS 指定的每个组的调用次数(您的本地组计数)。不多也不少