opengl:glFlush()对阵glFinish()

jay*_*lee 101 c c++ opengl graphics

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

文档说glFlush()并且glFinish()会将所有缓冲操作推送到OpenGL,以便可以确保它们都将被执行,区别在于glFlush()直接返回作为glFinish()块的所有操作都完成.

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

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

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

while (running) {
    process_stuff();
    render_stuff();
}
Run Code Online (Sandbox Code Playgroud)

Mal*_*sen 91

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

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

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


And*_*oss 21

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


Tar*_*ara 14

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

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

在底部我们看到一个使用的示例glFinish().它几乎做同样的事情glFlush(),除了它使调用线程等到所有命令都被硬件处理.

图像取自"使用OpenGL进行高级图形编程"一书.

  • 我实际上知道 `glFlush` 和 `glFinish` 的作用,但我不知道该图像在说什么。左边和右边各是什么?另外,该图像是在公共领域发布的还是在某些允许您将其发布到互联网上的许可下发布的? (2认同)

And*_*Dog 6

看看这里。简而言之,它说:

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

一篇文章描述了其他差异:

  • 交换函数(用于双缓冲应用程序)自动刷新命令,因此无需调用 glFlush
  • glFinish 强制 OpenGL 执行未完成的命令,这是一个坏主意(例如使用 VSync)

总而言之,这意味着您在使用双缓冲时甚至不需要这些函数,除非您的交换缓冲区实现不会自动刷新命令。


Bah*_*bar 6

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

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

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

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

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

  • 在"现在,你为什么要打电话给glFinish".如果你在一个线程上加载资源(例如:textures)并使用它们在另一个线程上渲染,通过wglShareLists或similars进行共享,你需要在向渲染线程发出信号之前调用glFinish,它可以自由地呈现异步加载的内容. (5认同)
  • 您不需要“需要”调用 glFinish,您可以使用同步对象。 (2认同)

sta*_*ole 5

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

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

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

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

  • 错误.正如我在上面的答案中留下的评论:如果你在一个线程上加载资源(例如:textures)并使用它们在另一个线程上渲染,通过wglShareLists或similars共享,你需要在发送给渲染线程之前调用glFinish它可以自由地呈现异步加载的内容.而且这不像你说的那样无操作. (4认同)
  • 必须处理损坏的纹理的个人经验,加上这个:http://higherorderfun.com/blog/2011/05/26/multi-thread-opengl-texture-loading/如果你考虑它,它是有道理的,但是因为它与线程之间的互斥或其他synch.api没有什么不同 - 在上下文可以使用共享资源之前,另一个必须完成该资源的加载,因此需要确保缓冲区已被清空.我认为更多的是规格的角落而不是bug,但我没有证据证明这个陈述:) (2认同)