着色器具有调用,每个调用都(通常)给出一组唯一的输入数据,并且每个(通常)都写入自己独立的输出数据。发出渲染命令时,每个着色器被调用多少次?
答案 0 :(得分:10)
每个着色器阶段都有自己的调用频率。我将使用OpenGL术语,但D3D的工作方式相同(因为他们都在建模相同的硬件关系)。
这是第二复杂的。它们为每个输入顶点执行一次......有点。如果使用非索引渲染,则比率恰好为1:1。每个输入顶点都将在单独的顶点着色器实例上执行。
如果使用索引渲染,则会变得复杂。它或多或少是1:1,每个顶点都有自己的VS调用。但是,由于后T& L缓存,顶点着色器可以执行 less 而不是每个输入顶点执行一次。
参见,假设顶点着色器的执行在输入顶点数据和输出顶点数据之间创建1:1映射。这意味着如果将相同的输入数据传递给顶点着色器(在同一渲染命令中),则需要生成相同的输出数据。因此,如果硬件可以检测到它将要在先前使用的相同输入数据上执行顶点着色器,则它可以跳过该执行并简单地使用先前执行的输出。
硬件通过使用顶点索引来检测到这一点(这就是为什么它不适用于非索引渲染)。如果向顶点着色器提供相同的索引,则假定着色器将获得所有相同的输入值,因此将生成相同的输出值。因此硬件将根据索引缓存输出值。如果索引在T& L后缓存中,则硬件将跳过VS的执行并仅使用输出值。
实例化只会稍微使后T& L缓存稍微复杂化。它不是仅仅根据顶点索引进行缓存,而是根据索引和实例 ID进行缓存。因此,如果两个值相同,它只使用缓存的数据。
一般来说,VS为每个顶点执行一次,但如果使用索引数据优化几何体,它可以执行的次数更少。有时很多更少,具体取决于你的工作方式。
或者用D3D说法的船体着色器。
TCS在这方面非常简单。它将在渲染命令的每个补丁中为每个顶点执行一次。这里没有进行缓存或其他优化。
或D3D用语域着色器。
在曲面细分基元生成器生成新顶点之后执行TES。因此,它的执行频率显然取决于您的镶嵌参数。
TES采用曲面细分生成的顶点并输出顶点。它以1:1的比例进行。
但与Vertex Shaders类似,每个输出图元中的每个顶点都不一定是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指定的每个组的调用次数(您的本地组计数)。不多也不少。