OpenGL - 切换着色器和统一变量是否经常成为严重瓶颈?

3

我目前正在规划一个渲染器,有两种不同的方式可以处理着色器。我已经为它们编写了伪代码:

示例 A

for all models {
  bind all vertex data for the model
  for each shader on this model {
    set shader
    upload uniforms
    draw indicies for this shader
  }
}

例子 B
for all models {
  collect geometry and seperate it by shader
}
sort geometry by shader into groups
for all shaders {
  set shader
  upload uniforms
  draw geometry group for this shader
}

示例 A 的优点是,我们只需要上传一次顶点数据,就可以共享所有几何图形。缺点是我必须不断更改着色器并上传到它的 uniform。
示例 B 的优势在于,我可以按着色器将整个场景中的所有几何图形排序,因此每个着色器只需应用 1 次,即可完成整个绘制过程。这也意味着,在任何给定时间内,我都会有更多的绘制堆栈,因此在一个着色器完成绘制后,"空闲" 时间更少。
哪种方式在性能上最好?基于我所了解的,我倾向于使用示例 B,但我想多学习一些关于它的知识。

1
你的性能分析告诉了你什么? - genpfault
1
测试场景复杂度/着色器复杂度/几何复杂度的所有排列组合并编写两个渲染器需要大量时间。我已经用Java / OpenGL编写了示例B,但现在我正在使用C++ / OpenGL进行开发,因此它不适用于测试案例。我希望有一个常见的实践方法或一篇好文章,或者只是一个非常聪明的人知道很多关于这个问题的知识哈哈。 - new Objekt
这取决于典型的工作量。 - Robinson
1个回答

3

通常情况下,涉及OpenGL的问题都取决于具体的实现(即驱动程序)。

例如,早期的NVidia驱动程序在Uniform值更改时往往会重新编译整个着色器(因此更改Uniform可能比切换纹理或着色器要昂贵得多)。后来,这个瓶颈被消除了,更改Uniform值变成了一个相当便宜的操作(比切换纹理或着色器更便宜)。

与所有性能相关的问题一样:您需要对程序进行分析并测试您的选项。


我希望能避免这种情况。要做两种实现并测试足够大的场景以获得良好的结果,这将是很多工作量。不过当你说“早期的Nvidia驱动程序”时,你是指像2007年还是1999年? - new Objekt
@newObjekt:最早支持GLSL的驱动程序应该是在2004年至2005年之间。我刚刚意识到我已经花了多少时间使用我的GeForce 8800(购买于2006年);它仍然没有退役,在过去几周里,我在工作中使用它来填补空缺,直到我的工作站得到一张新卡。 - datenwolf
我认为2005年已经够旧了,可以肯定地说它不会是我的游戏引擎的目标硬件。此外,我在2005年就拥有了一张Geforce 8600显卡。那张卡真是太棒了,哈哈。如果我没记错的话,它在经过6年的重度使用后部分熔化了。 - new Objekt
@newObjekt:GeForce8xxx系列于2006年10月/11月末发布 - 这只是挑刺而已。 - datenwolf
啊,是的,我大部分都是猜的。已经有一段时间了。不过还是谢谢你的建议。 - new Objekt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接