我正在尝试使用glew和glfw创建示例应用程序。主循环很简单,看起来像:
while (running) {
someUsefullMathHere();
renderer->render(timeDelta);
glfwSwapBuffers(window);
glfwPollEvents();
running = running & (!glfwWindowShouldClose(window));
}
问题是,由于vsync当前线程在glfwSwapBuffers执行中休眠了一段时间(fps限制为60 fps)。我正在寻找一种方法来利用这段时间连续执行someUsefullMath方法。理想情况下,代码必须如下所示:
while (running) {
while (!timeToRenderAndSwap()) {
someUsefullMathHere();
}
renderer->render(timeDelta);
glfwSwapBuffers(window);
glfwPollEvents();
running = running & (!glfwWindowShouldClose(window));
}
有办法吗?
3条答案
按热度按时间k5hmc34c1#
现代GL实现通常不会在
SwapBuffers
上阻塞,即使VSync打开也是如此。它们将提前几个帧对GL命令进行排队,并且仅在达到特定于实现的排队帧数限制后才在SwapBuffers
上阻塞(顺便说一句,nvidia的windows驱动程序对此有一个明确的设置)。这导致这样的情况,即,典型地,循环的前两到五次迭代将不会阻塞,而每个后续迭代将阻塞。有了相当现代的GL,你可以利用sync objects来改善这种情况。在伪代码中,这可能看起来像这样:
这利用了
SwapBuffers
不会立即阻塞的事实,并且会一直使用它,直到实际执行了缓冲区交换,以便执行有用的数学运算。这也有一个副作用,就是将延迟限制在一帧,这可能是好事也可能是坏事,这取决于你的场景。但是原则上,你也可以交错几个围栏同步对象,然后等待倒数第二个缓冲区交换,而不是最后一个,等等。
xzv2uavs2#
唯一可行的方法是为
someUsefulMathHere()
函数使用thread。(例如mutex,这只是其中一种可能性),或者将新作业排队。这样,您不仅可以在主线程真正休眠时获得空闲的CPU周期,但您也可以在多核CPU上获得额外的性能。0aydgbwb3#
首先,我想指出的是,即使没有vsync
glfwSwapBuffers(window)
也会阻塞一段时间。OpenGL的许多函数只是将命令放入队列中,并在不等待完成的情况下返回。这意味着,当您调用glfwSwapBuffers(window)
时,显卡仍可能有大量工作。此函数将等待所有工作完成后,再交换缓冲区并返回。我不确定
someUsefullMathHere()
的工作类型,因此我有两个可能的答案:如果需要对每帧执行特定数量的计算:
通常,除了渲染之外,你还需要每帧更新一次场景。为了更新场景,你需要每帧都做一些计算。你可以简单地把这个代码放在
glfwSwapBuffers(window)
之前,而不是放在循环的开头或结尾。这样你就可以在不使用线程的情况下获得更高的帧速率。我认为,如果程序只是等待vsync,应该没有什么区别,但如果您必须等待显卡,则应该有区别:如果要将时间用于跨帧的某些工作:
有时候你必须做一些需要花费太多时间的事情。比如加载关卡或者下载数据。为了利用缓冲区被交换的时间来做类似的事情,你可以使用第二个线程。我认为你可以在运行循环的剩余部分时暂停线程,以避免竞争情况: