I created a custom OpenGLView instead of using NSOpenGLView
by following Apple's docs. 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. But if I use dispatch_sync/dispatch_async
in display link drawing seems correct. But I'm not sure how it can hurt performance.
Q1: Is it right to use dispatch_sync in displaylink cb? 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. Since main thread is not dedicated to opengl , I don't know how it can affect FPS or cocoa controls. So Is it possible to run opengl drawing operations in separate thread?
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]);
}