为 NSView 初始化/同步 OpenGL 的正确方法
Correct way to initialize / sync OpenGL for NSView
我按照 Apple 的文档创建了自定义 OpenGLView 而不是使用 NSOpenGLView
。绘图看起来不错,只是我这里似乎有线程同步问题。由于 NSView 应该在主线程中然后如何同步线程,我的意思是 CADisplayLink
似乎在不同的线程上工作所以在旋转或缩放到 3D 场景后一些节点保持它们的旧变换(缓慢变换)直到 rotation/zooming 完成.但是如果我在显示中使用 dispatch_sync/dispatch_async
link 绘图似乎是正确的。但我不确定它会如何影响性能。
Q1:在显示link cb中使用dispatch_sync是否正确?或者什么是更好的选择?
Q2:我也没有画到全屏视图,会有 cocoa 控件或者可能有多个 openglviews。由于主线程不专用于 opengl ,我不知道它如何影响 FPS 或 cocoa 控件。那么是否可以 运行 在单独的线程中进行 opengl 绘图操作?
对于 zoom/rotation 情况我有一个解决方案,我在场景或节点中添加一个标志(当 zoom/rotation 更改时),然后在渲染函数中我检查该标志然后应用变换。 rendering/drawing 似乎也是正确的。但这是一种情况;将来还会有其他一些问题。所以我认为我需要同步线程
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 渲染可以发生在任何线程上,只要它一次只发生在一个线程上。仅仅因为你有一个 NSView 并不意味着你的上下文必须在主线程上呈现。
参见下面的示例。渲染是在显示 link 的线程上完成的,除了在主线程上发生的视图帧更改通知期间,因此代码使用锁在主线程上渲染该帧(实际上不是必要,但如果您这样做,锁会显示如何操作)。
https://developer.apple.com/library/content/samplecode/GLFullScreen/Introduction/Intro.html
我按照 Apple 的文档创建了自定义 OpenGLView 而不是使用 NSOpenGLView
。绘图看起来不错,只是我这里似乎有线程同步问题。由于 NSView 应该在主线程中然后如何同步线程,我的意思是 CADisplayLink
似乎在不同的线程上工作所以在旋转或缩放到 3D 场景后一些节点保持它们的旧变换(缓慢变换)直到 rotation/zooming 完成.但是如果我在显示中使用 dispatch_sync/dispatch_async
link 绘图似乎是正确的。但我不确定它会如何影响性能。
Q1:在显示link cb中使用dispatch_sync是否正确?或者什么是更好的选择?
Q2:我也没有画到全屏视图,会有 cocoa 控件或者可能有多个 openglviews。由于主线程不专用于 opengl ,我不知道它如何影响 FPS 或 cocoa 控件。那么是否可以 运行 在单独的线程中进行 opengl 绘图操作?
对于 zoom/rotation 情况我有一个解决方案,我在场景或节点中添加一个标志(当 zoom/rotation 更改时),然后在渲染函数中我检查该标志然后应用变换。 rendering/drawing 似乎也是正确的。但这是一种情况;将来还会有其他一些问题。所以我认为我需要同步线程
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 渲染可以发生在任何线程上,只要它一次只发生在一个线程上。仅仅因为你有一个 NSView 并不意味着你的上下文必须在主线程上呈现。
参见下面的示例。渲染是在显示 link 的线程上完成的,除了在主线程上发生的视图帧更改通知期间,因此代码使用锁在主线程上渲染该帧(实际上不是必要,但如果您这样做,锁会显示如何操作)。
https://developer.apple.com/library/content/samplecode/GLFullScreen/Introduction/Intro.html