哪个更好?
要指定一个带有大量制服的着色器程序 要使用的灯或要做的映射(例如,我需要一个网格进行视差映射,另一个网格视差/镜面映射)。我会制作一个缓存转移制服的缓存列表,如果需要的话,只需为每个下一个网格更换一些制服。
为每个需要的案例设置了很多着色器程序,每个案例都有少量制服,并为每个网格做 glUseProgram 的懒惰绑定如果它需要这样做。在这里,我假设网格已正确批处理,以避免冗余切换。
答案 0 :(得分:28)
我认识的大多数现代引擎都有一个“着色器缓存”并使用第二个选项,因为它显然更快。
您还可以查看允许动态链接的ARB_shader_subroutine。但我认为它只适用于DX11类硬件。
答案 1 :(得分:15)
通常情况下,除非您拥有真正庞大的程序,否则选项2将更快/更好。您还可以使用跨程序共享的缓冲区对象,以便在更改程序时无需重置任何值。
此外,链接程序后,您可以释放链接到程序中的所有着色器。这将释放所有源代码和驱动程序保留的任何预链接信息,只留下内存中完全链接的程序。
答案 2 :(得分:0)
我倾向于认为这取决于具体的应用。是的,因为说100个节目,每个节目各有约2-16个制服会更有效率;对两者进行权衡可能会更好。我倾向于认为,对于你最常见的着色技术,可能会说10到20个程序就足够了或者更多。例如,您可能希望有一个程序/着色器来执行所有凹凸贴图,一个用于执行所有雾效果,一个用于执行反射,一个用于执行折射。
现在超出你的问题的范围,我认为它也适用于你的引擎,有一件事就是BatchProcess& BatchManager类设置可以减少CPU的数量 - 通过总线进行GPU调用,因为这也证明是有效的。我不认为你的问题有一个适合所有解决方案,因为我认为这将是应用程序特定的,就像建立你的引擎将有多少批次(桶)的顶点(基元)之间的关系和多少每个批次的顶点都包含。
试图让这一点变得更清楚:一个游戏可能有4个容器或批次,其中每个批次最多可以容纳10,000个顶点,在BatchManager决定清空将所有这些顶点发送到的桶之前,它被视为已满要处理和绘制渲染管道的图形卡,其中不同的游戏可能有10个具有5,000个顶点的桶,或者另一个游戏可能有8个桶,其中12,0000个顶点。
因此可以根据您的需要尝试将两者结合起来。如果你有一个单一的程序与100多个制服;单个程序在管道中更容易管理,但着色器的读取和管理过于繁琐。然后再次使用很少制服的着色器非常容易阅读和管理,但在链接和发送它们以便正确呈现之前,拥有100个程序在CPU上管理起来有点困难。我个人试图找到一个中间地带,我有足够的程序来完成彼此完全独特的每个特定任务,例如在一个上进行雾密度,在另一个上进行体积阴影映射,其中每个程序都有足够的制服来做需要的计算。
接下来的步骤是做一些基准测试,看看你的效率和开销在哪里平衡,以进行适当的调整。