在macOS Mojave上OpenGL无法渲染

6
如果在macOS Mojave上创建一个NSView和自定义的NSOpenGLContext,则窗口直到重新调整大小之前不会被渲染。但如果使用NSOpenGLView,一切都可以正常工作。 我看到了很多的hack方法,在渲染之前通过编程方式调整窗口大小(http://people.bath.ac.uk/abscjkw/ComputerPrograms/C++programs/OpenGL/MojaveOpenGL.cpp)或者调用[NSOpenGLContext update]两次(https://github.com/go-gl/glfw/pull/229/commits/9e6129a572227a13ff9acb4904443d2ae7d66e77),但它们似乎非常不可靠和hacky。
3个回答

5
我拆开了苹果的框架并发现他们已经改变了 Mojave 上 OpenGL 渲染的工作方式。即使你通过设置 NSViewwantsLayerNO 来禁用分层支持,Mojave 上的 NSView 仍然会创建并附加一个图层到你的视图上。在渲染之前改变窗口大小可以工作是因为这通常会调用 [NSOpenGLContext update]。调用两次更新方法可以起作用,因为在第一帧中,NSView 没有图层附加到它上面,并且更新方法什么也不做,但在第二帧中,图层存在并且 [NSOpenGLContext update] 实际上初始化了帧缓冲。

所以解决方案是在设置 NSView 的图层时手动调用 [NSOpenGLContext update],像这样:

@interface OpenGLView: ViewMacOS
{
    NSOpenGLContext* _openGLContext;
}
@end

@implementation OpenGLView

-(void)setLayer:(CALayer*)layer
{
    [super setLayer:layer];

    [_openGLContext update];
}

@end

我测试过它,在Mojave和旧版本的macOS上都可以正常工作(在macOS 10.13及更早版本中未调用[NSView setLayer:])。这是我为Ouzel引擎所做的完整提交:https://github.com/elnormous/ouzel/commit/7e708636189d970bad6b013ecd5375cfe693f3f3

我有一点困难将[_openGLContext update]放在setLayer()回调函数中。因此,我在每帧渲染的开头调用[_openGLContext update]。它运行良好,只是不确定会引起多少额外开销。 - Hongkun Wang
@HongkunWang 我建议在setLayer中找到一种方法来实现它。这是[NSOpenGLContext update]的反汇编代码:https://pastebin.com/TXnUDGMn。正如您所看到的,它会分离和附加屏幕外表面,清除可绘制区域,设置虚拟屏幕并初始化新表面。我测量了一下,在我的MacBook Pro Mid 2015上运行macOS Mojave时,它花费了从170到1900微秒(平均470),而在我的MacBook Pro Late 2011上运行macOS High Sierra时,它花费了从140到600微秒(平均171)。 - Elviss Strazdins
感谢您提供的详细信息,它确实会导致一些性能损失。但是我不确定在macOS和iOS上我们可以使用OpenGL多久,所以我已经决定尽快开始使用Metal API。 - Hongkun Wang
1
它也可以与NSOpenGLView一起使用,在我添加了setLayer方法之后,一切都很好!这是最好的解决方案,谢谢你! - Art Golf
@ElvissStrazdins,你能展示一下从10.14.4升级到10.14.5版Mojave的变化吗?每当我调整我的NSOpenGLView的大小时,它会在错误的位置渲染视图,看起来向上偏移了。此外,如果您能帮助我理解如何反汇编苹果框架代码,这样我就可以自己找到问题所在。非常感谢您提前的帮助,我已经尝试了3个星期了。 - Amit Hooda

0

在升级到Mojave 10.14.3和Xcode 10.1之后,此问题已得到解决。


0
在我手动管理NSOpenGLContext的NSView子类中,我需要调用NSView.displayIfNeeded而不是NSView.display来进行缓冲区交换。重写NSView.setLayer并调用NSOpenGLContext.update没有帮助。
请注意,我的使用方式类似于SDL,我使用自定义运行循环,因此这可能不适用于海报程序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接