opengl:glFlush()对阵glFinish()

时间:2010-01-26 22:41:17

标签: c++ c opengl graphics

我无法区分调用glFlush()glFinish()之间的实际区别。

文档说glFlush()glFinish()会将所有缓冲的操作推送到OpenGL,以便可以确保它们都将被执行,区别在于glFlush()会立即返回到glFinish()阻止所有操作完成。

阅读完定义后,我认为如果我使用glFlush(),我可能会遇到向OpenGL提交更多操作而不是执行的问题。所以,只是为了尝试,我换了glFinish()glFlush()并且看,我的程序运行(据我所知),完全相同;帧率,资源使用情况,一切都是一样的。

所以我想知道这两个调用之间是否存在很大差异,或者我的代码是否使它们运行没有区别。或者应该使用哪一个而不是另一个。 我还认为OpenGL会有一些像glIsDone()这样的调用来检查glFlush()的所有缓冲命令是否完整(因此不会比OpenGL更快地向OpenGL发送操作)执行),但我找不到这样的功能。

我的代码是典型的游戏循环:

while (running) {
    process_stuff();
    render_stuff();
}

8 个答案:

答案 0 :(得分:88)

请注意,这些命令自OpenGL早期就存在。 glFlush确保以前的OpenGL命令必须在有限的时间内完成OpenGL 2.1 specs,第245页)。如果直接绘制到前缓冲区,这将确保OpenGL驱动程序开始绘制而不会有太多延迟。当你在每个对象之后调用glFlush时,你可以想到一个复杂的场景,它出现在屏幕上的对象后面。但是,当使用双缓冲时,glFlush几乎没有任何影响,因为在交换缓冲区之前,更改将不可见。

glFinish 在完全实现之前发出的命令[...]的所有效果之前不会返回。这意味着程序的执行会在此处等待,直到绘制完每个最后一个像素,OpenGL无需执行任何操作。如果直接渲染到前缓冲区,glFinish是在使用操作系统调用截取屏幕之前调用make。它对于双缓冲没那么有用,因为你没有看到你被迫完成的更改。

所以如果你使用双缓冲,你可能不需要glFlush和glFinish。 SwapBuffers隐式地将OpenGL调用指向正确的缓冲区there's no need to call glFlush first。并且不介意强调OpenGL驱动程序:glFlush不会扼杀太多命令。无法保证此调用立即返回 (无论这意味着什么),因此可能需要处理命令所需的任何时间。

答案 1 :(得分:21)

正如其他答案所暗示的那样,根据规范确实没有好的答案。 glFlush()的一般意图是在调用它之后,主机CPU将没有与OpenGL相关的工作 - 命令将被推送到图形硬件。 glFinish()的一般意图是,在它返回后,剩下没有剩余的工作,结果也应该是所有适当的非OpenGL API(例如从帧缓冲区读取,截图,等等...)。这是否真的发生了依赖于驱动因素。该规范允许大量的合法范围。

答案 2 :(得分:13)

我也总是对这两个命令感到困惑,但这张图片让我很清楚: Flush vs Finish 显然,除非累积了一定数量的命令,否则某些GPU驱动程序不会将发出的命令发送到硬件。在此示例中,该数字 5 该图显示了已发布的各种OpenGL命令(A,B,C,D,E ...)。正如我们在顶部看到的那样,命令还没有发出,因为队列还没有完整。

在中间我们看到glFlush()如何影响排队的命令。它告诉驱动程序将所有排队的命令发送到硬件(即使队列尚未填满)。这不会阻止调用线程。它只是告诉驱动程序我们可能不会发送任何其他命令。因此等待队列填满会浪费时间。

在底部,我们看到使用glFinish()的示例。它与glFlush()几乎完全相同,只是它使调用线程等到所有命令都被硬件处理完毕。

图像取自“使用OpenGL进行高级图形编程”一书。

答案 3 :(得分:6)

如果你没有看到任何性能差异,那就意味着你做错了什么。正如其他人提到的那样,你也不需要调用,但是如果你调用glFinish,那么你将自动失去GPU和CPU可以实现的并行性。让我深入一点:

实际上,您提交给驱动程序的所有工作都是批处理的,并且可能稍后发送到硬件(例如,在SwapBuffer时间)。

所以,如果你正在调用glFinish,那么你实际上是强迫驱动程序将命令推送到GPU(它直到那时才进行批处理,从未要求GPU继续工作),并使CPU停止运行直到命令推完全执行。因此,在GPU工作的整个时间内,CPU不会(至少在此线程上)。在CPU完成其工作(主要是批处理命令)的所有时间里,GPU都没有做任何事情。所以是的,glFinish会伤害你的表现。 (这是一个近似值,因为驱动程序可能会开始让GPU在某些命令上工作,如果它们中的很多已经批处理。虽然这不常见,因为命令缓冲区往往足够大,可以容纳很多命令)。 / p>

现在,你为什么要打电话给glFinish呢?我使用它的唯一时间是我有驱动程序错误。实际上,如果您向硬件发送的命令之一崩溃了GPU,那么确定哪个命令是罪魁祸首的最简单方法是在每次Draw之后调用glFinish。这样,您可以缩小究竟是什么触发崩溃

作为旁注,像Direct3D这样的API根本不支持Finish概念。

答案 4 :(得分:5)

glFlush确实可以追溯到客户端服务器模型。您通过管道将所有gl命令发送到gl服务器。那管道可能会缓冲。就像任何文件或网络i / o可能缓冲一样。 glFlush只说“现在发送缓冲区,即使它还没有填满!”。在本地系统上,这几乎从不需要,因为本地OpenGL API不太可能缓冲自身并且只是直接发出命令。所有导致实际渲染的命令都会执行隐式刷新。

另一方面,glFinish用于性能测量。 GL服务器的PING类型。它往返于命令并等待,直到服务器响应“我闲置”。

如今,现代的本地司机都有非常有创意的想法,这意味着闲置的意义。它是“所有像素被绘制”还是“我的命令队列有空间”?还因为许多旧程序在他们的代码中散布了glFlush和glFinish而没有理由像许多现代驱动程序一样编码,只是将它们视为“优化”。真的,不能责怪他们。

总而言之:除非您编写古老的远程SGI OpenGL服务器,否则请将glFinish和glFlush视为无操作。

答案 5 :(得分:4)

看看here。简而言之,它说:

  

glFinish()与glFlush()具有相同的效果,另外glFinish()将阻塞,直到所有提交的命令都被执行。

另一个article 描述了其他差异:

  • 交换功能(在双缓冲应用程序中使用)自动刷新命令,因此无需调用glFlush
  • glFinish强制OpenGL执行未完成的命令,这是一个坏主意(例如使用VSync)
总之,这意味着在使用双缓冲时甚至不需要这些函数,除非你的swap-buffers实现没有自动刷新命令。

答案 6 :(得分:3)

似乎没有办法查询缓冲区的状态。有这个Apple extension可以起到同样的作用,但它似乎并不是跨平台的(没有尝试过。)快速浏览一下,它似乎先于你flush推动fence命令;然后,您可以在缓冲区中移动时查询该栅栏的状态。

我想知道你是否可以在缓冲命令之前使用flush,但在开始渲染下一帧之前,你调用finish。这将允许您在GPU工作时开始处理下一帧,但如果在您返回时没有完成,finish将阻止确保所有内容都处于新状态。

我没试过,但我会很快。

我在一个具有相当CPU和CPU的旧应用程序上尝试过它。 GPU使用。 (它最初使用finish。)

当我在结束时将其更改为flush并在开始时将其更改为finish时,没有立即出现问题。 (一切看起来都很好!)程序的响应性增加了,可能是因为CPU没有停止在GPU上等待。绝对是一种更好的方法。

为了进行比较,我从框架的开头删除finished,留下flush,并执行相同的操作。

所以我会说使用flushfinish,因为当调用finish时缓冲区为空时,没有性能损失。而且我猜测缓冲区是否已满,你应该想要finish

答案 7 :(得分:0)

问题是:您希望代码在执行OpenGL命令时继续运行,还是仅在执行OpenGL命令后运行

在网络延迟等情况下,在绘制图像之后只有某些控制台输出时,这可能很重要。