and*_*wrk 14 opengl multithreading
我正在使用OpenGL创建一个图形用户界面应用程序,其中可以有任意数量的窗口 - "多文档界面"样式.
如果有一个窗口,主循环可能如下所示:
但是当有3个窗口时考虑主循环:
糟糕...现在呈现应用程序的一个帧发生在适当帧率的1/3处.
一种解决方法是只打开一个带有vsync的窗口,其余的带有vsync的窗口关闭.首先在vsync窗口上调用swapBuffers()并绘制一个,然后在每个窗口上绘制其余的窗口和swapBuffers().
这种解决方法在大多数情况下可能看起来很好,但它并非没有问题:
由于每个线程可以绑定一个OpenGL上下文,因此答案是每个窗口有一个线程.
我仍然希望GUI是单线程的,所以3窗口情况的主循环看起来像这样:
(对于每个窗口)
这会有用吗?这个问题表明它不会:
事实证明,窗口彼此"战斗":看起来SwapBuffers调用是同步的并且彼此等待,即使它们在不同的线程中.我正在测量每个窗口的帧到帧时间,并且有两个窗口,这下降到30 fps,有3到20 fps等.
为了调查这个说法我创建了一个简单的测试程序.该程序创建N个窗口和N个线程,每个线程绑定一个窗口,请求每个窗口启用vsync,然后报告帧速率.到目前为止,结果如下:
我想到的另一个想法是:只有一个OpenGL上下文和一个大的帧缓冲区,所有窗口的大小放在一起.
每个帧,每个窗口调用glViewport以在绘制之前设置它们各自的帧缓冲矩形.
完成所有绘图后,在唯一的OpenGL上下文中使用swapBuffers().
我即将调查这种解决方法是否有效.我有一些问题是:
glViewport每帧多次调用吗?这不是glViewport的工作原理.这不是缓冲区交换的工作方式.每个窗口都有一个帧缓冲区.你不能让他们分享一个.缓冲区交换是每个窗口帧缓冲区,上下文一次只能绑定到一个窗口.这是OS级别而不是GLFW的限制.
这个问题表明该算法可能有效:
Activate OpenGL context on window 1
Draw scene in to window 1
Activate OpenGL context on window 2
Draw scene in to window 2
Activate OpenGL context on window 3
Draw scene in to window 3
For all Windows
SwapBuffers
Run Code Online (Sandbox Code Playgroud)
问题提问者,
启用V-Sync后,SwapBuffers将同步到最慢的监视器,而速度更快的监视器上的窗口将变慢.
看起来他们只是在Microsoft Windows上对此进行了测试,并不清楚这个解决方案是否可以在任何地方使用.
还有许多消息来源告诉我makeContextCurrent()在draw()例程中太慢了.
它看起来也不符合EGL的规范.为了让另一个线程eglSwapBuffers(),你必须eglMakeCurrent(NULL),这意味着你eglSwapBuffers现在应该返回EGL_BAD_CONTEXT.
所以,我的问题是:解决使用vsync的多窗口应用程序问题的最佳方法是什么?这似乎是一个常见问题,但我还没有找到令人满意的解决方案.
与此问题类似:将多个OpenGL窗口同步到vsync,但我想要一个与平台无关的解决方案 - 或者至少是每个平台的解决方案.
这个问题:使用SwapBuffers()与多个OpenGL画布和垂直同步?但实际上这个问题与Python无关.
交换缓冲区(vsync导致此阻塞,直到垂直监视器刷新)
不,它不会阻止.缓冲区交换调用可以立即返回而不是阻塞.然而它的作用是插入一个同步点,以便延迟执行改变后台缓冲区的命令,直到发生缓冲区交换.OpenGL命令队列的长度有限.因此,一旦命令队列已满,进一步的OpenGL调用将阻止该程序,直到可以将其他命令推入队列.
缓冲交换也不是OpenGL操作.它是一个图形/窗口系统级操作,独立于OpenGL上下文.只需看看缓冲交换函数:它们采用的唯一参数是drawable(= window)的句柄.实际上,即使您在单个drawable上运行多个OpenGL上下文,也只需将缓冲区交换一次; 你可以在没有OpenGL上下文的情况下完成当前的绘制.
所以通常的做法是:
' first do all the drawing operations
foreach w in windows:
foreach ctx in w.contexts:
ctx.make_current(w)
do_opengl_stuff()
glFlush()
' with all the drawing commands issued
' loop over all the windows and issue
' the buffer swaps.
foreach w in windows:
w.swap_buffers()
Run Code Online (Sandbox Code Playgroud)
由于缓冲区交换没有阻塞,您可以为所有窗口发出所有缓冲区交换,而不会因V-Sync而延迟.但是,下一个OpenGL绘图命令可以解决为交换而发出的后台缓冲区的问题.
解决方法是使用FBO进行实际绘制,并将其与在交换缓冲区循环之前将FBO blit连接到后台缓冲区的循环组合:
' first do all the drawing operations
foreach w in windows:
foreach ctx in w.contexts:
ctx.make_current(w)
glBindFramebuffer(GL_DRAW_BUFFER, ctx.master_fbo)
do_opengl_stuff()
glFlush()
' blit the FBOs' renderbuffers to the main back buffer
foreach w in windows:
foreach ctx in w.contexts:
ctx.make_current(w)
glBindFramebuffer(GL_DRAW_BUFFER, 0)
blit_renderbuffer_to_backbuffer(ctx.master_renderbuffer)
glFlush()
' with all the drawing commands issued
' loop over all the windows and issue
' the buffer swaps.
foreach w in windows:
w.swap_buffers()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4919 次 |
| 最近记录: |