windows - Windows 上的 glfwSwapBuffers() 和垂直刷新

标签 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() 的轮询循环.我尝试了这种方法并且它几乎有效,但是由于轮询循环 sleep ,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 的轮询计时器更好的方法?

最佳答案

我认为你的问题已经通过一个奇怪的时间巧合解决了。 This commit几天前刚刚添加到 GLFW 的 master 分支,它正在删除 GLFW_USE_DWM_SWAP_INTERVAL因为他们现在使用 DWM 的 DWMFlush()使用 DWM 时进行同步的 API。此提交的更改日志包括:

  • [Win32] Removed GLFW_USE_DWM_SWAP_INTERVAL compile-time option
  • [Win32] Bugfix: Swap interval was ignored when DWM was enabled


因此,您可能只需要为 GLFW 获取最新的 git HEAD。

关于windows - Windows 上的 glfwSwapBuffers() 和垂直刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30437756/

相关文章:

c++ - CreateProcess 失败 - 错误 183

c - reshape() 函数在 glut 中有什么用?

c - GLFW 按键回调同步

c++ - 如何确定 Windows 10 中是否打开了高对比度主题?

c# - 报告完成后共享目标契约(Contract)崩溃

windows - 定义这些批处理命令

c++ - GLFW_PRESS抛出 “lvalue required as left operand of assignment”

java - LWJGL OpenGL glGenVertexArrays() 错误 : This Function is not available

java - 在 OpenGL 中获取相机在 X、Y 和 Z 轴上的弧度旋转?

c++ - GLFW getkey 'esc' 并关闭窗口