3

我正在开发一个应用程序,该应用程序需要以至少等于显示器刷新率的刷新率使用 OpengGL 进行绘制。而且我需要在单独的线程中执行绘图,以便绘图永远不会被激烈的 UI 操作锁定。

实际上,我正在使用 a NSOpenGLViewCVDisplayLink并且我能够毫无问题地达到 60-80FPS。

由于我还需要在此视图之上显示一些可可控件,因此我尝试按照LayerBackedOpenGLView Apple 示例进行子类NSOpenGLView化并使其具有图层支持。

结果并不令人满意,我得到了很多工件。

因此,我已经解决了这个问题,使用单独NSWindow的可可控件托管并将此窗口添加为包含NSOpenGLView. 它工作正常,我能够获得与初始实现完全相同的 FPS。

由于我认为这个解决方案很像一个肮脏的黑客,我正在寻找一种替代的、更干净的方式来实现我所需要的。

几天前我遇到了NSOpenGLLayer,我认为它可以用作解决我的问题的可行解决方案。

所以最后,在所有这些序言之后,我的问题来了:是否可以使用回调NSOpenGLLayer从单独的线程中绘制到 a ?CVDisplayLink

到目前为止,我已经尝试实现这一点,但我无法从CVDisplayLink回调中提取。我只能-setNeedsDisplay:TRUE在回调中执行绘图,然后在NSOpenGLLayer可可自动调用它时执行绘图。但我想这样我是从主线程中绘制的,不是吗?CVDisplayLink-drawInOpenGLContext:pixelFormat:forLayerTime:displayTime:

在谷歌搜索之后,我什至发现了这个帖子,其中用户声称在 Lion 下绘图只能发生在里面-drawInOpenGLContext:pixelFormat:forLayerTime:displayTime:

我目前在 Snow Leopard 上,但即使在 Lion 上,该应用程序也应该可以完美运行。

我错过了什么吗?

4

1 回答 1

4

是的,这是可能的,但不推荐。display从 CVDisplayLink 中调用图层。这将导致canDrawInContext:...被调用,如果它返回 YES,drawInContext:...将被调用,并且所有这些都在调用的任何线程上display。要使渲染图像在屏幕上可见,您必须调用[CATransaction flush]. Apple 邮件列表中已建议使用此方法,尽管它并非完全没有问题(其他视图的显示方法也可能在您的后台线程上调用,并且并非所有视图都支持从后台线程渲染)。

推荐的方法是使图层异步并在主线程上渲染 OpenGL 上下文。如果您无法以这种方式获得良好的帧速率,因为您的主线程在其他地方很忙,建议宁愿将其他所有内容(几乎是您的整个应用程序逻辑)移动到其他线程(例如使用 Grand Central Dispatch)并且只保留用户输入和在主线程上绘制代码。如果您的窗口非常大,您可能仍然无法获得比 30 FPS(每两次屏幕刷新一帧)更好的结果,但这是因为 CALayer 合成似乎是一个相当昂贵的过程,并且它已经或多或少地进行了优化静态层(例如包含图片的层)而不是用于更新自身 60 FPS 的层。

例如,如果您正在编写 3D 游戏,建议您根本不要将 CALayers 与 OpenGL 内容混合。如果您需要 Cocoa UI 元素,请将它们与您的 OpenGL 内容分开(例如,将窗口水平拆分为仅显示 OpenGL 的部分和仅显示控件的部分)或自己绘制所有控件(这在游戏中很常见)。

最后但并非最不重要的一点是,两窗口方法并不像您想象的那么奇特,这就是 VLC(视频播放器)如何在视频图像上绘制其控件(这也是由 Mac 上的 OpenGL 渲染的)。

于 2012-07-11T17:09:52.807 回答