C++ 与基本逻辑代码相比,OpenGL GLDrapureElements()调用的负担有多大?

C++ 与基本逻辑代码相比,OpenGL GLDrapureElements()调用的负担有多大?,c++,opengl,C++,Opengl,我计划在我的OpenGL程序上做一些优化(它不需要优化,但我是为了优化而做的)。出于好奇,OpenGL绘图函数与基本逻辑代码相比有多贵?目前,我正在做一个游戏的开始,在这个游戏中,屏幕上充满了方块,以表示一个二维块状的景观。这意味着对正方形(两个三角形)的绘制调用被多次调用。目前,我计划添加一些代码,查看块在当前帧中的位置,并将它们分组在一起。例如,如果有一列有7个块高,我可以调用一个函数,在整个屏幕上绘制一个1 x 7的矩形,以此类推,而不是执行7个单独的drawBlock()函数(其中包含g

我计划在我的OpenGL程序上做一些优化(它不需要优化,但我是为了优化而做的)。出于好奇,OpenGL绘图函数与基本逻辑代码相比有多贵?目前,我正在做一个游戏的开始,在这个游戏中,屏幕上充满了方块,以表示一个二维块状的景观。这意味着对正方形(两个三角形)的绘制调用被多次调用。目前,我计划添加一些代码,查看块在当前帧中的位置,并将它们分组在一起。例如,如果有一列有7个块高,我可以调用一个函数,在整个屏幕上绘制一个1 x 7的矩形,以此类推,而不是执行7个单独的drawBlock()函数(其中包含glDrawElements()调用)


如果计算要绘制什么的代码实际上比单独绘制块要占用更多的CPU,我就不必费心这么做了。

无法真正估计
glpaurements
(或任何其他)的成本。这是因为它的成本在很大程度上取决于在draw调用之间更改的OpenGL状态。调用OpenGL状态更改函数(基本上,任何不是某种形式的glGet或某种形式的glDraw的OpenGL函数)的成本相对较快。但这会使下一次抽签变慢

显示绘制时哪些状态更改的成本高于其他更改。真正好的部分大约在31分钟后开始

如果在绘制调用之间未更改任何OpenGL状态,则绘制调用相对较快。不同的状态对抽签调用有不同的影响。从最快到最慢(根据NVIDIA上面的介绍,所以请谨慎对待):

  • 非UBO统一更新
  • (不更改格式)
  • 变化
  • 纹理绑定
  • 片段状态变化
  • 着色器程序更改
  • 开关

现在,抽签调用将比“基本逻辑”更昂贵。它们并不便宜,即使它们之间没有状态变化。如果效率对代码很重要,那么将方块分组是一个好主意。

实际数字高度依赖于平台和供应商。不同操作系统上的驱动程序体系结构差别很大,其中一些体系结构比其他体系结构更高效。除此之外,驱动程序实现和硬件可能会导致很大的性能差异。例如,在相同的平台上,使用类似的硬件,一个供应商的draw呼叫吞吐量是另一个供应商的10-20倍

基于此,下面的任何数字都只是一个非常粗略的数量级。您确实需要根据自己关心的配置来衡量这一点

有了所有这些免责声明,我希望draw调用可以在100条指令(CPU周期)的范围内处理。在这种情况下,您只需进行背对背的draw调用,并且管道中没有其他瓶颈

正如@Nicolabolas已经指出的,处理draw调用最昂贵的部分通常是处理延迟状态更改。大多数情况下,绘制调用之间的状态会发生更改。在这种情况下,对于相对便宜的状态更改(如绑定纹理或缓冲区,或更改某些属性),典型的是100条指令

交换帧缓冲区通常非常昂贵,而且在某些平台上非常昂贵。除此之外,我过去在优化和基准测试状态变化时测量的数字表明,顺序与@Nicolabolas答案中的列表大不相同。但同样,这高度依赖于平台和供应商/硬件

还有几个方面使得这一点难以衡量:

  • 大部分CPU时间可能不会在线程中消耗。许多驱动程序都是多线程的,这意味着处理OpenGL调用所需的大部分工作都被转移到了辅助线程。若您的应用程序并没有使用所有的CPU内核,并且您并没有受到功率/热量限制的限制,这意味着许多驱动程序工作可以并行进行,而不会使您的应用程序慢很多。但特别是在移动设备和笔记本电脑上,性能往往受到功耗的限制,因此驱动程序开销仍然会降低速度
  • 驱动程序消耗的CPU时间只是降低应用程序代码速度的一部分。另一个考虑因素是缓存污染。如果应用程序使用的缓存内容在OpenGL实现处理绘制调用时被逐出,那么您自己的代码将获得更多的缓存未命中,并且运行速度会变慢。因此,测量OpenGL调用中花费的时间只显示了部分情况

我不确定你的问题与
元素的关系如何。听起来你在试图决定合并相邻的四边形是否值得;在这种情况下,决定这一点的最佳方法是通过剖析。@ColonelThirtyTwo:通常情况下,剖析是正确的,但在这种情况下,这是一个必然的结论
glpaurements
是出了名的昂贵。调用
glpaurements()
非常非常昂贵。我建议将所有背景块放在一个VBO中,然后可以对整个背景调用一次
glDrawerElements()
。或者把它分成块,如果太大的话…但是每个
gldrawerelements()
一个四元组不会导致每个帧有很多四元组。我一直到最后一句话“…但是每个
gldrawerelements()
一个四元组不会导致每个帧有很多四元组”嗯,这就是我现在正在做的,所以如果它不会产生很多四边形,你的意思是我应该使它更有效吗?不过,将顶点添加到数组似乎有点做作!无论如何,谢谢你的帮助:)