首页 文章

opengl:glFlush()对阵glFinish()

提问于
浏览
94

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

文档说 glFlush()glFinish() 会将所有缓冲操作推送到OpenGL,这样可以确保它们全部被执行,区别在于 glFlush() 会立即返回 glFinish() 阻塞,直到所有操作完成 .

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

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

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

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

8 回答

  • 6

    请注意,这些命令自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不会扼杀太多命令 . 不保证此调用立即返回(无论这意味着什么),因此它可能需要任何时间来处理您的命令 .

  • 11

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

  • 4

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

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

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

    从书"Advanced Graphics Programming Using OpenGL"拍摄的图像 .

  • 0

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

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

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

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

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

  • 81

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

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

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

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

  • 5

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

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

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

    • 交换函数(用于双缓冲应用程序)自动刷新命令,因此无需调用 glFlush

    • glFinish 强制OpenGL执行未完成的命令,这是一个坏主意(例如使用VSync)

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

  • 3

    似乎没有办法查询缓冲区的状态 . 有这个Apple extension可以起到同样的作用,但它并没有尝试过 . )快速浏览一下,看起来好像是在推动围栏命令;然后,您可以在缓冲区中移动时查询该栅栏的状态 .

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

    我没有试过这个,但我会很快 .

    我已经尝试过一个使用CPU和GPU的旧应用程序 . (它原来使用 finish . )

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

    为了比较,我从帧的开头删除了 finished ,留下 flush ,并执行相同的操作 .

    所以我会说使用 flushfinish ,因为在调用 finish 时缓冲区为空时,没有性能损失 . 我是猜测缓冲区是否已满,无论如何你应该想要 finish .

  • 21

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

    在网络延迟等情况下,只有在绘制图像之后才能获得某些控制台输出,这一点很重要 .

相关问题