简体   繁体   English

为NSView初始化/同步OpenGL的正确方法

[英]Correct way to initialize / sync OpenGL for NSView

I created a custom OpenGLView instead of using NSOpenGLView by following Apple's docs. 我遵循苹果的文档创建了一个自定义OpenGLView而不是使用NSOpenGLView Drawing seems fine except it seems I have thread sync issues here. 绘图似乎很好,但似乎我这里有线程同步问题。 Since NSView should be in main thread then how to sync threads, I mean CADisplayLink seems work on different thread so after rotating or zooming to 3D scene some nodes keep their old transform (transformed slowly) until rotation/zooming finished. 由于NSView应该在主线程中,然后在如何同步线程中,我的意思是CADisplayLink似乎在不同的线程上工作,因此在旋转或缩放到3D场景后,某些节点会保持其旧的转换(缓慢转换),直到旋转/缩放完成为止。 But if I use dispatch_sync/dispatch_async in display link drawing seems correct. 但是如果我在显示链接绘图中使用dispatch_sync/dispatch_async似乎是正确的。 But I'm not sure how it can hurt performance. 但是我不确定它如何影响性能。

Q1: Is it right to use dispatch_sync in displaylink cb? Q1:在displaylink cb中使用dispatch_sync是否正确? Or what is the better alternative? 还是更好的选择?

Q2: Also I'm not drawing to full screen view, there will be cocoa controls or maybe multiple openglviews. Q2:另外我没有绘制全屏视图,会有可可控件或多个openglviews。 Since main thread is not dedicated to opengl , I don't know how it can affect FPS or cocoa controls. 由于主线程不是专用于opengl的,所以我不知道它如何影响FPS或可可粉控件。 So Is it possible to run opengl drawing operations in separate thread? 那么可以在单独的线程中运行opengl绘图操作吗?

For zoom/rotation case I have a solution, I'm adding a flag (when zoom/rotation changed) to scene or node then in rendering func I'm checking that flag then applying transforms. 对于缩放/旋转情况,我有一个解决方案,我向场景或节点添加了一个标志(更改缩放/旋转时),然后在渲染功能时,我检查了该标志然后应用了变换。 And rendering/drawing seems also correct. 渲染/绘图似乎也是正确的。 But this is one case; 但这是一种情况。 there would be some other issues in the future. 将来还会有其他问题。 So I need to sync threads I think 所以我需要同步我认为的线程

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

OpenGL rendering can happen on any thread, as long as it only happens on one thread at a time. OpenGL渲染可以在任何线程上进行,只要一次只在一个线程上进行即可。 Just because you have an NSView doesn't mean your context must render on the main thread. 仅仅因为您拥有NSView并不意味着您的上下文必须在主线程上呈现。

See the example below. 请参见下面的示例。 The rendering is done on the display link's thread, except during the view frame change notification which happens on the main thread, so the code uses a lock to render that one frame on the main thread (which is not actually necessary, but if you do, the lock shows how to do it). 呈现是在显示链接的线程上完成的,除了在主线程上发生视图框架更改通知期间外,因此代码使用锁在主线程上呈现该一帧(这实际上不是必需的,但是如果您这样做,该锁将显示操作方法)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM