Macos 同步两个NSOpenGLView的flushBuffer
我正在开发一个OSX应用程序,它由两个Macos 同步两个NSOpenGLView的flushBuffer,macos,opengl,flush,nsopenglview,Macos,Opengl,Flush,Nsopenglview,我正在开发一个OSX应用程序,它由两个nsopenggleviews(leftGLView和rightlview)组成,并排放置在NSWindow contentView中。 这两个视图不共享NSOpenGLContext,但都是双缓冲的,并将缓冲区交换与监视器回程同步 设置CVDisplayLink并将其链接到第一个NSOpenGLView的NSOpenGLContext和NSOpenGLPixelFormat(如左侧) 在CVDisplayLink回调中,我使用以下代码绘制两个视图: -(C
nsopenggleview
s(leftGLView
和rightlview
)组成,并排放置在NSWindow contentView中。
这两个视图不共享NSOpenGLContext
,但都是双缓冲的,并将缓冲区交换与监视器回程同步
设置CVDisplayLink
并将其链接到第一个NSOpenGLView
的NSOpenGLContext
和NSOpenGLPixelFormat
(如左侧)
在CVDisplayLink回调中,我使用以下代码绘制两个视图:
-(CVReturn)draw {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
CGLLockContext([[leftGLView openGLContext] CGLContextObj]);
[[leftGLView openGLContext] makeCurrentContext];
... draw code ...
[[leftGLView openGLContext] flushBuffer];
CGLUnlockContext([[leftGLView openGLContext] CGLContextObj]);
CGLLockContext([[rightGLView openGLContext] CGLContextObj]);
[[rightGLView openGLContext] makeCurrentContext];
... draw code ...
[[rightGLView openGLContext] flushBuffer];
CGLUnlockContext([[rightGLView openGLContext] CGLContextObj]);
[pool release];
return kCVReturnSuccess;
}
这种方法的问题是,两个flushBuffer
并不总是同步的。右侧NSOpenGLView的更新有时晚于左侧(可能在下次监视器刷新期间)。
这并非完全出乎意料,因为苹果关于-flushBuffer
的文档中指出:
根据交换间隔上下文属性(请参见
NSOpenGLCPSwapInterval),可在垂直
返回监视器,而不是在刷新缓冲区后立即返回
打电话。隐式glFlush在返回之前由flushBuffer完成。
为了获得最佳性能,应用程序不应调用glFlush
在调用flushBuffer之前后续OpenGL命令可以
在调用flushBuffer后立即发出,但不执行
直到缓冲区复制完成。
但是,在这种情况下,我有两个不同的NSOpenGLContext
,因此可以同时刷新两个缓冲区
为了进一步研究这一点,我假设-flushBuffer
仅在交换(或复制)缓冲区后返回,并且由于这仅与监视器回溯同步发生,因此对flushBuffer的第二次调用将太晚,无法在该回溯上发生。这可以解释我观察到的行为。
因此,我尝试分离一个辅助线程来执行flushBuffer调用,但没有任何区别
我终于尝试使用两种不同的CVDisplayLink
s,一种用于左侧GLView,另一种用于右侧GLView。然而,这种技术似乎也不能解决问题,并且增加了保持两个CVDisplayLink线程同步的额外复杂性
有没有办法让两个NSOpenGLView之间的两个
flushBuffer
同步进行?在交换之前将每个上下文设置为不同线程的当前上下文。否则,启用VSYNC后,您的帧速率将不必要地减少一半。@AndonM.Coleman:谢谢您的回复。当我尝试使用两个线程(每个视图一个)时,我只是这样做了,这改善了情况,但并没有完全解决问题。在我发布的示例中,我只使用了一个线程,但帧速率仍然是60fps。我不明白如何将帧速率减半。如果使用VSYNC,则每次交换都将在VBLANK之后完成。使用VSYNC进行缓冲区交换最简单的实现是交换操作本身阻塞,直到VBLANK(监视器的垂直回溯间隔)滚动。因此,在最坏的情况下(假设刷新率为60 Hz),两次背对背交换将需要33.33334 ms。在最好的情况下,它们将需要略高于16.66667的时间。无论在何种情况下,除非您从两个单独的线程驱动交换链,否则您的一个窗口将始终落后于另一个窗口。@AndonM.Coleman:谢谢,我现在明白了。你知道为什么有时候即使我从两个独立的线程驱动交换,一个视图仍然落后一帧吗?这比使用单个线程要好得多,但仍然不够完美。仍然不能保证两个线程能够提前足够长的时间交换缓冲区,以便在VBLANK之前完成。即使在单窗口应用程序中也可以看到这一点,如果它们在VBLANK之前约1ms交换缓冲区,则帧可能无法及时完成,最终结果是显示2帧的旧帧,而新帧稍微延迟。你可以考虑的一件事实际上是在一个线程中完成这一切,但是只在一个窗口上使用VSyc。假设第一个块的缓冲区交换直到VBLANK,并且您可以及时完成第二个窗口的帧,这可能会起作用