Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 线程在SwapBuffers()中被阻塞时获取消息()_Windows_Multithreading_Winapi_Opengl_Message Queue - Fatal编程技术网

Windows 线程在SwapBuffers()中被阻塞时获取消息()

Windows 线程在SwapBuffers()中被阻塞时获取消息(),windows,multithreading,winapi,opengl,message-queue,Windows,Multithreading,Winapi,Opengl,Message Queue,Vsync阻塞SwapBuffers(),这正是我想要的。我的问题是,由于输入消息与窗口的所有者是同一个线程,因此在SwapBuffers()被阻止时传入的任何消息都不会立即被处理,而只有在vsync触发缓冲区交换并返回SwapBuffers()之后才会被处理。因此,我的所有计算线程都处于空闲状态,而不是使用最近的输入处理场景以便在下一帧中渲染。我特别关心的是延迟非常低。我需要某种方法从其他线程访问窗口中所有挂起的输入消息 Windows API提供了一种使用MsgWaitForMultiple

Vsync阻塞SwapBuffers(),这正是我想要的。我的问题是,由于输入消息与窗口的所有者是同一个线程,因此在SwapBuffers()被阻止时传入的任何消息都不会立即被处理,而只有在vsync触发缓冲区交换并返回SwapBuffers()之后才会被处理。因此,我的所有计算线程都处于空闲状态,而不是使用最近的输入处理场景以便在下一帧中渲染。我特别关心的是延迟非常低。我需要某种方法从其他线程访问窗口中所有挂起的输入消息

Windows API提供了一种使用MsgWaitForMultipleObjects()等待Windows事件或输入消息的方法,但没有类似的方法与其他方法一起等待缓冲区交换。那太不幸了

我考虑过在另一个线程中调用SwapBuffers(),但这要求在向SwapBuffers()发送另一个线程的信号之前在窗口的线程中调用glFinish(),而glFinish()仍然是一个阻塞调用,因此这不是一个好的解决方案

我曾考虑过上钩,但那看起来也是个死胡同。挂接WH_GETMESSAGE将使GetMsgProc()不是异步调用的,而是当窗口的线程调用GETMESSAGE()/PeekMessage()时,因此没有帮助。安装全局钩子对我也没有帮助,因为需要使用特定的窗口句柄调用RegisterTouchWindow()来处理WM_TOUCH,而我的输入是TOUCH。而且,对于鼠标和键盘,您可以安装低级挂钩,在消息发布到线程队列时捕获消息,而不是在线程调用GetMessage()/peek message()时,touch似乎没有类似的选项

我还研究了wglDelayBeforeSwapNV(),但我不知道是什么阻止操作系统在调用该函数之后、但在SwapBuffers()之前抢占线程,从而导致下一个vsync信号丢失


那么什么是好的解决方法呢?我是否可以创建第二个不可见的窗口,在可见窗口显示渲染时,该窗口将始终处于活动状态,从而获取所有输入消息?根据另一个讨论,仅消息窗口(带有HWND_消息的CreateWindow)与WM_TOUCH不兼容。是否有一些SwapBuffers()在内部等待的未记录事件,我可以访问并提供给MsgWaitForMultipleObjects()?我的目标是一个固定平台(Windows8.164位),所以如果存在未记录的功能,我可以使用它。不过,我确实不想编写自己的触摸屏驱动程序。

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

SwapBuffers(…)
也不一定会阻塞。根据VSYNC的要求,当所有backbuffers都挂起交换时,实现只需阻止下一个修改backbuffer的命令。通过引入第二个backbuffer,三重缓冲稍微改变了一些情况

三重缓冲的一种可能实现方式是在交换时丢弃最旧的backbuffer,因此
SwapBuffers(…)
永远不会导致阻塞(这就是现代版本的Windows在启用DWM的窗口模式下的有效工作方式)。其他实现最终将同时显示两个backbuffers,这会减少(但不会消除)阻塞,但也会导致显示延迟帧


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

如果我在另一个线程上创建没有窗口的OpenGL上下文,我将无法显示它(除非我在屏幕外渲染,然后将其复制到窗口,这显然会挫败降低延迟的尝试)。(此外,我已经通过驱动程序设置使用了三重缓冲。)多个上下文何时进入讨论?我是否遗漏了什么?我的错误。第一句话不相关,因此我将其删除。您可以轻松地从创建窗口的线程以外的线程中绘制。您所要做的就是通过调用
wglMakeCurrent从创建窗口/上下文的线程中放弃上下文(NULL,NULL)
。然后,一旦启动了GL的工作线程,就可以将相应的
wglMakeCurrent(…)
调用并执行该线程中的所有GL命令。Win32消息泵实际上是创建窗口的线程唯一相关且不可变的地方,这就是我建议将GL移动到单独线程中的原因。等等,这里可能存在问题。我引用:“Nvidia告诉我这是因为DeviceContext实际上是线程仿射的,GDI函数只能在创建它们的线程中对它们进行调用。引用Nvidia的话,“使用非HDC仿射线程的HDC调用GDI函数总是错误的(OpenGL是GDI api,像HDC这样的GDI对象是线程仿射的),但一般来说,失败案例很难纠正。”