【问题标题】:Draw from a separate thread with NSOpenGLLayer使用 NSOpenGLLayer 从单独的线程中绘制
【发布时间】:2012-02-25 08:52:24
【问题描述】:

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

实际上,我将NSOpenGLViewCVDisplayLink 结合使用,我能够毫无问题地达到60-80FPS。

由于我还需要在此视图上显示一些可可控件,因此我尝试继承 NSOpenGLView 并使其具有层支持,遵循 LayerBackedOpenGLView Apple 示例。

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

因此,我使用单独的NSWindow 来托管可可控件并将此窗口添加为包含NSOpenGLView 的主窗口的子窗口,从而解决了该问题。 它运行良好,我能够获得与初始实现完全相同的 FPS。

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

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

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

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

在谷歌搜索后,我什至发现this 帖子中用户声称在Lion 下绘图只能发生在-drawInOpenGLContext:pixelFormat:forLayerTime:displayTime: 内。

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

我错过了什么吗?

【问题讨论】:

    标签: multithreading cocoa layer nsopenglview nsopengl


    【解决方案1】:

    是的,这是可能的,但不推荐。从您的 CVDisplayLink 中调用图层上的display。这将导致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 渲染)。

    【讨论】:

    • 谢谢!目前的应用程序也是一个视频播放器。我不知道 VLC 使用子窗口作为它的控件,我从来没有看过它的源代码。虽然子窗口解决方案似乎在 iMac 上运行良好,但另一方面,它似乎在 2009 款 MacBook 上出现了一些图形问题。但我不确定这些问题是否与子窗口或其他有关。我会尝试你在我的另一个问题上建议的解决方案,如果它不能提供更好的性能,我会坚持使用控件的子窗口。非常感谢!!
    • 我将 performSelectorOnMainThread 与 CVDisplayLink 结合使用。而且效果很好。如果您使用 CATransaction .Flush,如果您尝试将用户交互与帧动画相结合,您将遇到问题。它可以使用,但您必须在以后的所有代码中考虑到它。更容易使用 performSelectorOnMainThread 方法。这是我和 Mecki 之间的对话,也是我在这个主题上的发现:chat.stackoverflow.com/rooms/104337/… 也希望你对这个 Mecki 发表最后的评论。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-27
    • 2019-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多