NSOpenGLView和CVDisplayLink,没有默认的帧缓冲区

时间:2013-11-19 22:03:46

标签: cocoa opengl

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

glCheckFramebufferStatus为GL_FRAMEBUFFER,GL_DRAW_FRAMEBUFFER和GL_READ_FRAMEBUFFER返回GL_FRAMEBUFFER_UNDEFINED。

文档中的信息:

  

如果target是默认值,则返回GL_FRAMEBUFFER_UNDEFINED   framebuffer,但默认的帧缓冲不存在。

以下是相关的代码:

- (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]);

}

2 个答案:

答案 0 :(得分:1)

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

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

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

NSOpenGLView *view = ...;

view.openglContext.view = view;

我很困惑,显然,即使NSOpenGLContext是由NSOpenGLView创建的,但仍然需要这样做,但它确实如此。

答案 1 :(得分:0)

诀窍是打开View Effects检查器并取消选中Core Animation Layer部分中的父View。

enter image description here