glfwSwapBuffers()和Windows上的垂直刷新

我想用OpenGL和GLFW做一些非常简单的事情:我想从左到右滚动一个100×100的白色填充的矩形,然后再回来。 矩形应该每帧移动1个像素,滚动应该是非常平滑的。 这是我的代码:

int main(void) { GLFWwindow* window; int i = 0, mode = 0; if(!glfwInit()) return -1; window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL); if(!window) { glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSwapInterval(1); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, 640, 0, 480, -1, 1); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3f(1.0, 1.0, 1.0); while(!glfwWindowShouldClose(window)) { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glRecti(i, 190, i + 100, 290); glfwSwapBuffers(window); glfwPollEvents(); if(!mode) { i++; if(i >= 539) mode = 1; } else { i--; if(i <= 0) mode = 0; } } glfwTerminate(); return 0; } 

在Mac OS X和Linux上,这个代码工作得很好。 滚动与垂直刷新完全同步,您看不到任何口吃或闪烁。 这真的非常顺利。

Windows上,事情更加困难。 默认情况下,启用桌面合成时, glfwSwapInterval(1)对Windows没有任何影响。 GLFW文档说这已经完成了,因为启用DWM合成启用交换间隔会导致严重的抖动。 这个行为可以通过定义GLFW_USE_DWM_SWAP_INTERVAL编译GLFW来改变。 在这种情况下,上面的代码在Windows上工作得很好。 滚动完全同步,没有抖动。 我在运行XP,Vista,7和8的各种不同的机器上testing过它。

但是,必须有一个非常好的理由,使得GLFW作者默认禁用Windows上的交换间隔,所以我认为有很多configuration会导致严重的抖动。 也许我很幸运,没有一台机器显示它。 因此,定义GLFW_USE_DWM_SWAP_INTERVAL并不是一个真正的解决scheme,因为默认情况下它必须被禁用,尽pipe它有点让我觉得GLFW团队没有提出更好的解决scheme,因为现在,由于这个问题,GLFW程序不是真正的便携式。 以上面的代码为例:它将在Linux和OS X上完全同步,但是在Windows上它将以闪电般的速度运行。 这在我看来有点违背了GLFW的可移植性概念。

鉴于GLFW_USE_DWM_SWAP_INTERVAL不能在Windows上使用的情况,因为GLFW团队明确警告它的使用,我想知道我应该做什么。 自然的解决scheme当然是一个计时器,它可以测量时间,并确保glfwSwapBuffers()不会比监视器的垂直刷新率更频繁地被调用。

但是,这也不像听起来那么简单,因为我不能使用Sleep()因为这太不精确了。 因此,我不得不使用QueryPerformanceCounter()的轮询循环。 我尝试了这种方法,它的工作原理非常有效,但是由于轮询循环睡眠,CPU使用率当然高达100%。 另一方面,当使用GLFW_USE_DWM_SWAP_INTERVAL ,CPU使用率仅为1%。

另一种方法是设置一个定时器,定期触发,但AFAIK的CreateTimerQueueTimer()的精度不是很令人满意,可能不会产生完全同步的结果。

长话短说:我想问一下处理这个问题的build议方法是什么? 上面的示例代码当然仅用于说明目的。 我一般的问题是,我正在寻找一种干净的方式,使glfwSwapBuffers()交换缓冲区与Windows上的显示器的垂直刷新同步。 在Linux和Mac OS X上,这已经可以正常工作,但是在Windows上,GLFW文档讨论的严重抖动问题(但是我没有在这里看到)。

我仍然有些困惑,GLFW并没有提供内置的解决scheme来解决这个问题,而且几乎让程序员解决了这个问题。 我仍然是OpenGL的新手,但从我的天真的angular度来看,我认为有一个function,交换缓冲区与垂直刷新同步是一个基本的重要性的特点,所以它逃脱了我为什么GLFW没有它在Windows上。

所以再次我的问题是:如何解决glfwSwapInterval()在Windows上无法正常工作的问题? 有什么build议的方法来解决这个问题? 有没有更好的方法比使用轮询定时器,会杀死CPU?

我认为你的问题在时间上遇到了一个奇怪的巧合。 这个提交已经在几天前被添加到GLFW的master分支,并且正在删除 GLFW_USE_DWM_SWAP_INTERVAL因为它们现在使用DWM的DWMFlush() API来在DWM使用时进行同步。 这个提交的更新日志包括:

  • [Win32]删除了GLFW_USE_DWM_SWAP_INTERVAL编译时选项
  • [Win32] Bugfix:启用DWM时,交换间隔被忽略

所以可能抓住GLFW最新的git HEAD是你需要做的。