正确初始化/同步OpenGL for NSView

时间:2018-01-06 12:50:07

标签: macos cocoa opengl nsview cadisplaylink

我按照Apple的文档创建了一个自定义OpenGLView,而不是使用NSOpenGLView。绘图看起来很好,除了看起来我在这里有线程同步问题。由于NSView应该在主线程中,然后如何同步线程,我的意思是CADisplayLink似乎在不同的线程上工作,所以在旋转或缩放到3D场景之后,一些节点保持它们的旧变换(缓慢变换)直到旋转/缩放完成。但是,如果我在显示链接图中使用dispatch_sync/dispatch_async似乎是正确的。但我不确定它会如何影响性能。

Q1:在displaylink cb中使用dispatch_sync是对的吗?或者更好的选择是什么?

Q2:我也没有画到全屏视图,会有可可控件或者多个openglviews。由于主线程不专用于opengl,我不知道它如何影响FPS或cocoa控件。那么可以在单独的线程中运行opengl绘图操作吗?

对于缩放/旋转情况,我有一个解决方案,我正在添加一个标志(当缩放/旋转更改时)到场景或节点然后在渲染功能我正在检查该标志然后应用变换。渲染/绘图似乎也是正确的。但这是一个案例;将来会有一些其他问题。所以我需要同步我认为的线程

CVReturn
displaylink_cb(CVDisplayLinkRef    CV_NONNULL  displayLink,
               const CVTimeStamp * CV_NONNULL  inNow,
               const CVTimeStamp * CV_NONNULL  inOutputTime,
               CVOptionFlags                   flagsIn,
               CVOptionFlags     * CV_NONNULL  flagsOut,
               void              * CV_NULLABLE displayLinkContext) {
  dispatch_sync(dispatch_get_main_queue(), ^{
    [(__bridge GLView *)displayLinkContext renderOnce];
  });

  return kCVReturnSuccess;
}

- (void)syncWithCurrentDisplay {
  NSOpenGLContext  *openGLContext;
  CGLContextObj     cglContext;
  CGLPixelFormatObj cglPixelFormat;
  GLint             swapInt;

  openGLContext = [self openGLContext];
  swapInt       = 1;

  /* Synchronize buffer swaps with vertical refresh rate */
  [openGLContext setValues: &swapInt
              forParameter: NSOpenGLCPSwapInterval];

  /* Create a display link capable of being used with all active displays */
  CVDisplayLinkCreateWithActiveCGDisplays(&m_displayLink);

  /* Set the renderer output callback function */
  CVDisplayLinkSetOutputCallback(m_displayLink,
                                 display_link_cb,
                                 (__bridge void *)self);

  /* Set the display link for the current renderer */
  cglContext     = [openGLContext CGLContextObj];
  cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
  CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(m_displayLink,
                                                    cglContext,
                                                    cglPixelFormat);
}

- (void) renderOnce {
  NSOpenGLContext *context;
  context = [self openGLContext];

  [context makeCurrentContext];

  /* because display link is threaded */
  CGLLockContext([context CGLContextObj]);
  [[self delegate] render];
  [context flushBuffer];
  CGLUnlockContext([context CGLContextObj]);
}

1 个答案:

答案 0 :(得分:1)

OpenGL渲染可以在任何线程上发生,只要它一次只发生在一个线程上。仅仅因为你有一个NSView并不意味着你的上下文必须在主线程上呈现。

请参阅下面的示例。渲染是在显示链接的线程上完成的,除了在主线程上发生的视图帧更改通知期间,因此代码使用锁来在主线程上呈现一个帧(这实际上不是必需的,但是如果你这样做的话) ,锁显示了如何做到这一点。)

https://developer.apple.com/library/content/samplecode/GLFullScreen/Introduction/Intro.html