我很难区分调用glFlush()和glFinish()的实际区别。
文档说glFlush()和glFinish()会将所有缓冲的操作推送到OpenGL,以便可以确保它们都将被执行,不同之处在于glFlush()立即返回,其中glFinish()阻塞,直到所有操作都被执行为止。完成。
阅读了定义之后,我发现如果使用glFlush(),可能会遇到向OpenGL提交比其可执行的操作更多的问题。因此,为了尝试,我将我的glFinish()换成了glFlush(),瞧瞧,我的程序运行了(据我所知),完全一样。帧速率,资源使用情况,一切都一样。
所以我想知道这两个调用之间是否有很大区别,或者我的代码是否使它们运行没有区别。还是应该使用一个与另一个。
我还发现OpenGL会调用glIsDone()之类的命令来检查glFlush()的所有缓冲命令是否完整(因此,向OpenGL发送操作的速度不会比执行它们快)。我找不到这样的功能。
我的代码是典型的游戏循环:
1 2 3 4
| while (running) {
process_stuff();
render_stuff();
} |
请注意,这些命令自OpenGL诞生以来就存在。 glFlush确保先前的OpenGL命令必须在有限时间内完成(OpenGL 2.1规格,第245页)。如果直接绘制到前缓冲区,则应确保OpenGL驱动程序开始绘制时不会有太多延迟。您可能会想到一个复杂的场景,当您在每个对象之后调用glFlush时,它们在屏幕上一个接一个地出现。但是,使用双缓冲时,glFlush实际上几乎没有任何作用,因为直到交换缓冲后更改才可见。
在完全实现先前发出的命令的所有效果之前,glFinish不会返回。这意味着程序的执行将在这里等待,直到绘制完每个最后一个像素,OpenGL不再需要执行其他操作。如果直接渲染到前端缓冲区,则在使用操作系统调用获取屏幕截图之前,将进行glFinish调用。对于双重缓冲,它用处不大,因为您看不到强制完成的更改。
因此,如果您使用双重缓冲,则可能不需要glFlush和glFinish。 SwapBuffers隐式将OpenGL调用定向到正确的缓冲区,无需先调用glFlush。而且不要介意OpenGL驱动程序:glFlush不会阻塞太多命令。不能保证此调用立即返回(无论这意味着什么),因此它可能需要任何时间来处理您的命令。
-
您是什么意思,glFlush"必须在有限的时间内完成",然后又说,glFlush将不会阻塞,因为"它可能需要任何时间来处理您的命令"? (帽雷)阿伦那些互斥?
-
只要它在某个时间点结束,就符合FINITE时间标准。一些驱动程序完全不操作此调用。
-
SwapBuffers是特定于上下文的,只需要刷新调用线程上下文。如果呈现多个上下文,则应手动刷新每个上下文,因为在通过另一个上下文交换缓冲区时不会保证发生这种情况。
正如其他答案所暗示的那样,按照规范,确实没有好的答案。 glFlush()的一般意图是,调用它后,主机CPU将无需执行与OpenGL相关的工作-命令将被推送到图形硬件。 glFinish()的一般意图是返回后,不会剩下任何剩余的工作,并且所有适当的非OpenGL API(例如从帧缓冲区,屏幕截图等读取的内容)也应可获得结果。那是否真的发生取决于驱动程序。该规范为合法性提供了很大的自由度。
我也总是对这两个命令感到困惑,但是这张图让我很清楚:

显然,除非累积了一定数量的命令,否则某些GPU驱动程序不会将发出的命令发送到硬件。在此示例中,该数字为5。
该图显示了已发出的各种OpenGL命令(A,B,C,D,E ...)。正如我们在顶部看到的那样,命令尚未发出,因为队列尚未满。
在中间,我们看到glFlush()如何影响排队的命令。它告诉驱动程序将所有排队的命令发送到硬件(即使队列尚未满)。这不会阻塞调用线程。它只是通知驱动程序我们可能不会发送任何其他命令。因此,等待队列填满将浪费时间。
在底部,我们看到了使用glFinish()的示例。它几乎与glFlush()做相同的事情,除了它使调用线程等待,直到所有命令都已被硬件处理为止。
图片摘自《使用OpenGL进行高级图形编程》一书。
-
我实际上知道glFlush和glFinish的作用,我无法分辨该图像在说什么。 左边和右边是什么? 另外,该图像是在公共领域发布还是在某种许可下发布的,允许您将其发布到Internet上?
-
我应该详细说明一下。 关于许可证:实际上我不太 在进行研究时,我偶然发现了Google上的PDF。
如果您没有发现任何性能差异,则说明您做错了什么。正如其他一些人提到的那样,您不需要调用任何一个,但是如果您调用glFinish,那么您将自动失去GPU和CPU可以实现的并行性。让我深入探讨:
实际上,您提交给驱动程序的所有工作都会被分批处理,并在以后可能的方式(例如在SwapBuffer时)发送到硬件。
因此,如果您要调用glFinish,则实际上是在迫使驱动程序将命令推送到GPU(直到那时批处理,并且从未要求GPU继续工作),并暂停CPU,直到完全推送了命令为止被执行。因此,在GPU整个工作期间,CPU不会工作(至少在此线程上)。而且,在CPU一直工作(主要是批处理命令)的所有时间中,GPU不会执行任何操作。是的,glFinish应该会损害您的性能。 (这是一个近似值,因为如果很多命令已经被批处理,驱动程序可能会开始让GPU处理某些命令。不过这并不典型,因为命令缓冲区往往足够大以容纳很多命令)。
现在,您为什么还要调用glFinish?我唯一使用过的时间是当我遇到驱动程序错误时。的确,如果您发送给硬件的命令之一使GPU崩溃,那么确定罪魁祸首的最简单选择就是在每次绘制之后调用glFinish。这样,您可以缩小触发崩溃的确切范围
附带一提,Direct3D之类的API根本不支持Finish概念。
-
在"现在,为什么要一直调用glFinish"上。如果您要在一个线程上加载资源(例如:纹理)并使用它们在另一线程上进行渲染,并通过wglShareLists或类似对象进行共享,则需要先调用glFinish,然后再向渲染线程发出信号,告知其可以自由渲染异步加载的内容。
-
就像我在下面说的,这确实看起来像是驱动程序错误的解决方法。我找不到有关此要求的任何规格说明。在Windows上,驱动程序必须锁定,在Mac上,您必须执行CGLLockContext。但是使用glFinish似乎非常错误。要知道纹理何时有效,在任何情况下都必须执行自己的锁定或事件。
-
opencl opengl interop docs建议使用glFinish进行同步"在调用clEnqueueAcquireGLObjects之前,应用程序必须确保访问mem_objects中指定的对象的所有未决GL操作均已完成。这可以通过在所有对象上发出并等待glFinish命令的完成来移植完成。 GL上下文以及这些对象的待定引用"
-
您无需"调用" glFinish,就可以使用同步对象。
-
补充一下,因为原始答案:某些GL实现开始使用flush / finish在不同线程上的共享上下文之间进行同步:developer.apple.com/library/ios/documentation/3DDrawing/-最著名的是Apple IOS。我认为从根本上讲,这是对API的另一种滥用。但这是对我原始答案的警告:在某些实现中,需要完成/刷新。但是定义实现的方式和原因,而不是OpenGL规范。
glFlush实际上可以追溯到客户端服务器模型。您通过管道将所有gl命令发送到gl服务器。该管道可能会缓冲。就像任何文件或网络I / O可能会缓冲一样。 glFlush只说"即使缓冲区尚未满,现在也要发送缓冲区!"。在本地系统上,这几乎是不需要的,因为本地OpenGL API不太可能自身缓冲,而是直接发出命令。同样,所有导致实际渲染的命令都将执行隐式刷新。
另一方面,glFinish用于性能测量。对GL服务器的一种PING。它往返执行一条命令,并一直等到服务器响应"我空闲"。
如今,现代的本地驾驶员已经有了非常有创意的想法,尽管闲着意味着什么。是"绘制了所有像素"还是"我的命令队列有空间"?同样是因为许多旧程序无缘无故地在其代码中撒满了glFlush和glFinish,因为伏都教编码使许多现代驱动程序只是将它们视为"优化"。真的不能怪他们。
因此,总而言之:在实践中,不要将glFinish和glFlush视作没有操作,除非您要为古老的远程SGI OpenGL服务器编码。
-
错误。就像我在上面的答案中留下的评论一样:如果要在一个线程上加载资源(例如:纹理)并使用它们在另一个线程上渲染,并通过wglShareLists或类似对象进行共享,则需要先调用glFinish,然后再向渲染线程发出信号它可以自由呈现已异步加载的内容。而且它不是您所说的禁止操作。
-
真?您能否支持在使用带有某些规范链接的共享库之前调用glFinish的需求?我完全可以看到需要这个的越野车司机。这又回到了我所说的。人们使用glFinish解决有问题的驱动程序。因此,可以正常工作的驱动程序会忽略它的性能。原始的规范使用情况分析(和单个缓冲渲染)不再起作用。
-
不得不处理损坏的纹理的个人经验以及以下内容:Higherorderfun.com/blog/2011/05/26/如果您考虑一下,这是有道理的,因为它与使用互斥锁或其他synch.api并没有太大区别线程之间-上下文可以使用共享资源之前,另一个必须完成该资源的加载,因此需要确保缓冲区已清空。我认为更多是规范的具体情况,而不是错误,但我对此声明没有证据:)
-
很棒的答案,谢谢。特别是"许多旧程序在其代码中撒满了glFlush和glFinish而没有理由成为巫毒教徒"。
-
真的没有行动吗? Arent glFinish和/或glFlush对于高强度图像处理或基于GPU的数学协处理具有很高的价值吗? 例如,直到调用glFinish以确保所有像素计算均已写入后,我们才从像素缓冲区向CPU读取GPU计算的结果。 我们错过了什么吗?
在这里看看。简而言之,它说:
glFinish() has the same effect as glFlush(), with the addition that glFinish() will block until all commands submitted have been executed.
另一篇文章介绍了其他差异:
-
交换功能(在双缓冲应用程序中使用)自动刷新命令,因此无需调用glFlush
-
glFinish强制OpenGL执行出色的命令,这不是一个好主意(例如使用VSync)
综上所述,这意味着使用双缓冲时甚至不需要这些功能,除非交换缓冲区实现不会自动刷新命令。
-
他已经知道了。它的问题。
-
是的,但是文档说两者都具有相同的效果,例如,关于窗户系统的差别很小。但是无论如何,我编辑了答案;)
-
很高兴在细微差别上大声疾呼。它阐明了是否有必要调用glFlush()和THEN glFinish()-(在阅读完上面所有内容之后,我们都遇到了一个问题。)
似乎没有一种查询缓冲区状态的方法。有一个Apple扩展程序可以达到相同的目的,但它似乎不是跨平台的(没有尝试过。)乍一看,在flush之前,您应该先推入fence命令。然后,您可以查询该围栏在缓冲区中移动时的状态。
我想知道是否可以在缓冲命令之前使用flush,但在开始渲染下一帧之前调用finish。这样一来,您就可以在GPU工作时开始处理下一帧,但是如果在返回时还没有完成,则finish会阻塞以确保一切都处于新状态。
我还没有尝试过,但是我会尽快的。 strike>
我已经在一个甚至可以使用CPU和GPU的旧应用程序上进行过尝试。 (它最初使用finish。)
当我将其更改为结尾处的flush和开始处的finish时,没有立即出现的问题。 (一切看起来都很好!)程序的响应能力增强了,这可能是因为CPU并没有在GPU上等待而停止。绝对是更好的方法。
为了进行比较,我从帧的开头删除了finished,保留了flush,并且执行了相同的操作。
所以我会说使用flush和finish,因为当调用finish的缓冲区为空时,不会影响性能。而且我猜测如果缓冲区已满,您还是应该要finish。
问题是:您是希望代码在执行OpenGL命令时继续运行,还是仅在执行OpenGL命令后才运行?
在某些情况下(例如由于网络延迟),只有在绘制图像等之后才具有某些控制台输出,这可能很重要。