在SwapBuffers()中阻塞线程时GetMessage()

时间:2014-05-19 20:27:03

标签: windows multithreading winapi opengl message-queue

Vsync阻止SwapBuffers(),这就是我想要的。我的问题是,由于输入消息转到拥有该窗口的同一个线程,因此在阻止SwapBuffers()时进入的任何消息都不会立即处理,而是仅在vsync触发缓冲区交换并且SwapBuffers()返回后才会处理。所以我让所有的计算线程都处于空闲状态,而不是使用最新的输入处理场景以便在下一帧中进行渲染。我特别担心延迟非常低。我需要一些方法来从其他线程访问窗口的所有待处理输入消息。

Windows API提供了一种使用MsgWaitForMultipleObjects()等待Windows事件或输入消息的方法,但是没有类似的方法可以将缓冲区交换与其他内容一起等待。这非常不幸。

我考虑过在另一个线程中调用SwapBuffers(),但是需要在窗口的线程中调用glFinish(),然后再将另一个线程发送到SwapBuffers(),而glFinish()仍然是一个阻塞调用,因此它不是一个好的解决方案

我考虑过挂钩,但这看起来也像死路一条。使用WH_GETMESSAGE挂钩将不会异步调用GetMsgProc(),但是当窗口的线程调用GetMessage()/ PeekMessage()时,它没有任何帮助。由于需要使用特定的窗口句柄调用RegisterTouchWindow()来处理WM_TOUCH,并且我的输入是触摸,因此安装全局钩子对我没有帮助。而且,对于鼠标和键盘,您可以安装低级挂钩,捕获消息,因为它们被发布到线程的队列中,而不是当线程调用GetMessage()/ PeekMessage()时,似乎没有类似的触摸选项

我还查看了wglDelayBeforeSwapNV(),但是我没有看到什么阻止操作系统在调用该函数之后但在SwapBuffers()之前有时抢占线程,导致错过下一个vsync信号。

那么什么是好的解决方法?我可以创建第二个不可见的窗口,它将以某种方式始终是活动的窗口,因此获取所有输入消息,而可见的窗口显示渲染?根据另一个讨论,仅消息窗口(具有HWND_MESSAGE的CreateWindow)与WM_TOUCH不兼容。是否有一些未记录的事件,SwapBuffers()在内部等待,我可以访问并提供给MsgWaitForMultipleObjects()?我的目标是一个固定的平台(Windows 8.1 64位)所以如果它存在,我可以使用未记录的功能。但我确实想避免编写自己的触摸屏驱动程序。

1 个答案:

答案 0 :(得分:2)

出于好奇,为什么不在另一个线程中实现你的整个绘图逻辑?您遇到的问题似乎是消息泵由绘制的同一个线程驱动。由于Windows不允许您从与创建窗口的线程不同的线程驱动消息泵,因此最简单的解决方案就是将所有GL内容推送到不同的线程中。

SwapBuffers (...)也不一定会阻止。根据VSYNC的要求,实现只需要阻止 next命令,这将修改后备缓冲区,而 所有 后备缓冲区正在等待交换。三重缓冲通过引入第二个后备缓冲器来改变一些东西。

三重缓冲的一种可能实现将在交换时丢弃最旧的后备缓冲区,因此SwapBuffers (...)永远不会导致阻塞(这实际上是现代版本的Windows在 窗口中工作的方式< / em> 模式,启用DWM)。其他实现最终会呈现两个反向缓冲区,这个减少(但不会消除)阻塞,但也会导致显示后期帧。

不幸的是,WGL不允许您请求交换链中的反向缓冲区数量(超过 0 单缓冲或 1 双缓冲);在Windows上获得三重缓冲的唯一方法是使用驱动程序设置。最低的消息延迟将来自于在另一个线程中驱动GL,但三重缓冲可以帮助一点点,而不需要你的努力。