2011-03-09 99 views
19

本主题与任何优化问题一样,受到很大冲击,但我无法找到我想要的东西。OpenGL低级性能问题

很多教程,甚至SO问题都有类似的提示;通常覆盖:

  • 使用GL面剔除(OpenGL的函数,而不是现场逻辑)
  • 仅发送1点矩阵到GPU(projectionModelView组合),因此每个模型减小MVP计算从每个顶点到一次(因为它应该是)。
  • 使用交错顶点
  • 尽量减少多达GL调用越好,一批酌情

,可能几个/许多其他问题。我(出于好奇的原因)使用几个顶点缓冲区在我的应用程序中渲染了2800万个三角形。我已经尝试了所有上述技术(据我所知),并且几乎没有收到性能改变。

虽然我在我的执行过程中接收到大约40FPS的数据,但这并不是问题,我仍然对这些优化的“提示”实际使用的位置感到好奇吗?

我的CPU在渲染过程中空转大约20-50%,因此我假设为我是用GPU来提高性能的。

注:我期待到gDEBugger此刻

跨张贴在Game Development

回答

25

1点是显而易见的,因为是节约填充率。如果首先处理物体背面的图元,则会忽略这些面。然而现代GPU容忍透支相当好。我曾经(GeForce8800 GTX)在重大性能受到影响之前测量了多达20%的透支。但最好将这个储备保留下来,比如遮挡剔除,混合几何图形的渲染等等。

点2是没有意义的。这些矩阵从未在GPU上计算过 - 如果不计算SGI Onyx的话。矩阵总是只是在CPU上计算的某种渲染全局参数,然后被推入GPU中的全局寄存器,现在称为统一体,所以加入它们只有很小的好处。在只保存一个额外的向量矩阵乘法(归结为4条MAD指令)的着色器中,代价是算法灵活性较低。第3点是关于缓存效率。属于一起的数据应该适合高速缓存行。

第4点是关于防止状态变化垃圾缓存。但它强烈依赖于GL所称的他们的意思。改变制服便宜。切换纹理非常昂贵。原因是,一个统一坐在寄存器中,而不是一些缓存的内存。切换着色器价格昂贵,因为不同的着色器会表现出不同的运行时行为,因此会破坏流水线执行预定义,更改内存(从而更改缓存访问模式等)。

但这些都是微观优化(其中一些具有巨大的影响)。不过,我建议寻求大的影响优化,例如实施早期Z通行证;在Z早期使用遮挡查询来快速区分整个几何批次。一个大的影响优化,主要包括总结许多类似微观优化的Point-4,是通过昂贵的GL状态来对渲染批次进行排序。所以把所有的东西都用普通的着色器分组,在这些组中按纹理排序等等。此状态分组只会影响可见的渲染过程。在早期的Z中,你只是在Z缓冲区上测试结果,所以只有几何变换,碎片着色器才会通过Z值。

+0

非常好!谢谢。 – 2011-03-09 10:36:25

+1

非常好的答案。有一个问题,在你对第2点的回答中,我有点困惑。我比较了着色器内部具有“model * projection * view”的差异(因为统一变量,每次模型更改时发送模型视图);与每个模型更新的单个统一矩阵变量(模型视图投影)相比较,该模型由CPU而不是每个顶点计算(一次)。当然,这会节省很多计算? – dcousens 2011-03-09 11:25:45

+3

@Daniel:你通常不会在着色器中计算MVP矩阵。你所做的是首先执行计算modelview_position = MV * vertex_position,然后clip_position = P * modelview_position。这背后的原因是,对于某些算法,您需要模型视图中转换的顶点位置,而不仅仅是整个投影过程的最终结果。此外,顶点法线仅由MV的逆转置来转换,而不是完整的MVP^T^-1,所以这是另一个原因:如果要实现光线良好,则需要这些转换后的法线。 – datenwolf 2011-03-09 11:33:00

1

这很大程度上取决于您正在运行的特定硬件以及使用场景是什么。 OpenGL的性能提示对于一般情况是有意义的 - 毕竟,该库是对许多不同驱动程序实现的抽象。 驱动程序制造商可以自由地进行优化,但是他们希望在引擎盖下进行优化,以便他们可以在您不知情的情况下移除冗余状态更改或执行其他优化。在另一台设备上,他们可能不会。最好坚持最佳实践,以便在各种设备上获得更好的性能。

+0

嗯,我想这可以看作是针对OpenGL的更少的优化,以及更接近图形编程的良好(和性能奖励)习惯。 – dcousens 2011-03-09 11:46:50

+0

最佳使用当前硬件加速图形库的一些一般经验法则是:不要经常更改状态和批量批处理批处理。然而,优化规则并不是在不同代硬件上建立的,现在的情况并非如此,对于所有过去的硬件来说都不是这样,而且未来的硬件可能并非如此。始终欣赏缓存以及您正在使用的硬件的限制和优势。 – Luther 2011-03-09 11:55:54

+0

我听说的理由是,针对特定硬件进行优化是愚蠢的行为,因为行为可能会在硬件世代之间甚至是驱动程序版本之间发生根本变化。您最好对API进行优化(在这种情况下,如前所述,最小状态变化),并让硬件赶上无法再优化的地方。 – Jherico 2012-12-27 07:27:51

3
  1. 没有意义的驱动程序可以结合这些矩阵为你(它知道他们的制服,所以平局通话过程中不会改变)。
  2. 只有当你的CPU必然

你需要知道的第一件事情就是到底是你的瓶颈。 GPU不是答案,因为它是一个复杂的系统。实际的问题可能是其中:

  • 着色处理(顶点/片段/几何)
  • 填充率
  • 绘制调用数
  • GPU < - > VMEM(这其中交织和更小的纹理帮助)
  • 系统总线(流的一些数据的每一帧?)

您需要进行一系列的测试,看看亲blem。例如,将所有内容都绘制到更大的FBO上,以查看它是否是填充率问题(或者增加MSAA量)。或者抽出一切两次来检查绘制的呼叫超载问题。

+0

你能解释一下为什么你说只有在应用程序被CPU绑定时才应该完成批处理? – ashishsony 2013-02-13 11:18:27

+0

(最初的答案是在2.5年前给出的,所以我试图回想我在想什么......)。在GPU方面,单次调用与其中的两半之间有一点区别。这是在驱动程序方面的调用准备就绪,这是在CPU上完成的。 – kvark 2013-11-14 15:19:10

3

只需将我的2美分添加到@kvark和@datenwolf答案中,我想说的是,尽管您提到的要点是“基本”GPU性能提示,但更多涉及的优化依赖于应用程序。

在你几何重的测试案例中,你已经投掷了2800万个三角形* 40 FPS = 1120万个三角形每秒 - 这已经相当多:大多数(并非所有,尤其是费米)GPU都有一个三角形设置每GPU时钟周期性能为1个三角形。这意味着以800MHz运行的GPU不能处理每秒超过8亿个三角形;这甚至没有绘制单个像素。 NVidia Fermi每个时钟周期可以处理4个三角形。

如果你达到了这个限制(你没有提到你的硬件平台),那么在OpenGL/GPU级别你可以做的不多。您只需发送更少的几何体,通过更高效的剔除(平截头体或闭塞)或通过LOD方案。

另一件事是,小的三角形伤害填充率,因为光栅化器在像素的方块上进行平行处理;见http://www.geeks3d.com/20101201/amd-graphics-blog-tessellation-for-all/

+0

有趣的链接,但它可能已被放大到“三角形和像素降压”的声明。而且还主要涉及LOD和其他稍微不同的优化。虽然很好的答案;我没有指出我的硬件规格,因为我没有在寻找硬件的具体提示。 – dcousens 2011-03-11 10:02:23