Windows上的glfwSwapBuffers()和垂直刷新

时间:2015-05-25 11:53:04

标签: windows opengl glfw

我想用OpenGL和GLFW做一些非常简单的事情:我想从左到右滚动一个100x100的白色填充矩形,然后再返回。矩形应该每帧移动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的各种不同机器上进行了测试。

但是,必须有一个很好的理由让GLFW作者默认禁用Windows上的交换间隔,所以我认为有很多配置确实会导致严重的抖动。也许我很幸运,我的机器都没有显示出来。所以定义GLFW_USE_DWM_SWAP_INTERVAL并不是一个我可以忍受的解决方案,因为默认情况下它必须有一个被禁用的原因,尽管GLFW团队没有提出更好的解决方案,因为它有点让我感到厌烦,因为现在看来,由于这个问题,GLFW程序并不是真正可移植的。以上面的代码为例:它将在Linux和OS X上完美同步,但在Windows上它将以闪电般的速度运行。这有点违背了GLFW在我眼中的便携性概念。

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

然而,这也不像听起来那么简单,因为我不能使用Sleep(),因为这太不精确了。因此,我必须使用QueryPerformanceCounter()的轮询循环。我尝试了这种方法,它几乎可以工作,但由于轮询循环睡眠,CPU使用率当然高达100%。另一方面,当使用GLFW_USE_DWM_SWAP_INTERVAL时,CPU使用率仅为1%。

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

简而言之:我想问一下处理这个问题的推荐方法是什么?上面的示例代码当然仅用于说明目的。我的一般问题是,我正在寻找一种简洁的方法,使glfwSwapBuffers()交换缓冲区与Windows上的监视器垂直刷新同步。在Linux和Mac OS X上,这已经运行良好,但在Windows上存在GLFW文档所讨论的严重抖动问题(但我在这里没有看到)。

我仍然有点困惑的是,GLFW没有为这个问题提供内置的解决方案,而且几乎让程序员无法解决这个问题。我仍然是OpenGL的新手,但从我天真的角度来看,我认为有一个功能可以将缓冲区与垂直刷新同步交换,这是一个至关重要的功能,所以它让我无法理解为什么GLFW在Windows上没有它。

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

0 个答案:

没有答案