cocoa - NSOpenGLView 和 CVDisplayLink,无默认帧缓冲区

标签 cocoa opengl

我有一个 NSOpenGLView 和 OpenGL 代码,可与在主循环中运行的 NSTimer 一起使用(调用 setNeedsDisplay 和 drawRect)。我想使用 CVDisplayLink,这样我就可以获得更好的帧速率,而不会过度驱动计时器。我从苹果的 OSXGLEssentials 示例中复制了大部分代码。显示链接启动并且回调运行,但屏幕上实际上没有绘制任何内容。 glGetError 返回 GL_INVALID_FRAMEBUFFER_OPERATION。

glCheckFramebufferStatus 对于 GL_FRAMEBUFFER、GL_DRAW_FRAMEBUFFER 和 GL_READ_FRAMEBUFFER 返回 GL_FRAMEBUFFER_UNDEFINED。

文档中的信息:

GL_FRAMEBUFFER_UNDEFINED is returned if target is the default framebuffer, but the default framebuffer does not exist.

以下是相关代码:

- (void)awakeFromNib {

  NSOpenGLPixelFormatAttribute attributes[] = {
    NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,   // Core Profile !
    NSOpenGLPFADoubleBuffer,
    NSOpenGLPFAAccelerated,
    NSOpenGLPFAColorSize, 24,
    NSOpenGLPFAAlphaSize, 8,
    NSOpenGLPFAAllowOfflineRenderers,
    0
  };

  NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
  NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:format shareContext: nil];
  // [context setView: self];
  [self setPixelFormat: format];
  [self setOpenGLContext: context];

}


- (void)prepareOpenGL {

  [super prepareOpenGL];

  NSOpenGLContext* context = [self openGLContext];
  [context makeCurrentContext];

  // Synchronize buffer swaps with vertical refresh rate
  GLint swapInt = 1;
  [context setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];

  MyDisplay_setup();
  MyDisplay_initScene(_bounds.size.width, _bounds.size.height);

  CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
  CVDisplayLinkSetOutputCallback(displayLink, &displayLinkCallback, (__bridge void *)self);
  CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
  CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [context CGLContextObj], cglPixelFormat);
  CVDisplayLinkStart(displayLink);

}


static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime,
CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) {

  @autoreleasepool {
    [(__bridge MyView*)displayLinkContext redraw];
  }
  return kCVReturnSuccess;

}


- (void)redraw {

  NSOpenGLContext* context = [self openGLContext];
  [context makeCurrentContext];
  CGLLockContext([context CGLContextObj]);
  MyDisplay_drawScene();
  CGLFlushDrawable([context CGLContextObj]);
  CGLUnlockContext([context CGLContextObj]);

}

最佳答案

这是一个老问题,但这个问题仍然存在,所以这是我的答案。作为引用,我根本不使用 Xcode,我在 Vim 中编写代码并使用 Clang 进行编译,所以这是默认行为,与 IB 无关。我仅使用 NSOpenGLView、NSOpenGLContext 和 CGDisplayLink 进行渲染。我有一台运行 macOS Sierra 的 MacBook Pro(视网膜屏,15 英寸,2014 年中)。

在调试时,我发现 NSOpenGLContext 的 view 属性在启动显示链接后的前几帧返回 nil。如果您在未附加 View 时进行任何渲染(glClear 除外),这足以破坏上下文,并导致相同的 GL_FRAMEBUFFER_UNDEFINED 错误。

我发现解决这个问题的最简单方法是在创建后将 NSOpenGLView 分配给它的 NSOpenGLContext,如下所示:

NSOpenGLView *view = ...;

view.openglContext.view = view;

我很困惑,显然,即使 NSOpenGLContext 是由 NSOpenGLView 创建的,也有必要这样做,但事实就是如此。

关于cocoa - NSOpenGLView 和 CVDisplayLink,无默认帧缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20083027/

相关文章:

ios - 升级Xcode后项目有bug

c++ - 在 Qml 场景下使用 OpenGL 渲染时出现奇怪的错误

python - PyQT5 OpenGL 4.1 核心配置文件 - 无效的帧缓冲区操作 - Mac OS

macos - 如何阻止 NSTableView 保存当前滚动位置?

iphone - XPath如何在不加载整个xml的情况下选择第一个元素?

c++ - 使用 GL_TEXTURE_MIN_FILTER GL_LINEAR 渲染效果不佳

c++ - OpenGL:将 VBO 与 std::vector 一起使用

c++ - OpenGL深度缓冲好像没有生效

objective-c - Webkit WebView 不工作

objective-c - 在 Xcode 中,如何从不断更新的文本文件中读取数据?