在Cocoa中,在循环内刷新NSOpenGLView而不释放主运行循环。

3
我正在构建一个Cocoa/OpenGL应用程序,每次需要控制每个视频帧并写入数字IO设备的时间段约为2秒。如果在进行OpenGL调用后我释放主线程(例如,如果我将OpenGL调用放在定时器fire-method中,并设置间隔为0.01秒),则每次调用glFinish()时都会刷新OpenGL视图。
但是,如果我像在一个长达2秒的while循环中保持主线程繁忙一样,OpenGL调用将不起作用(令人惊讶的是,第一次调用glFinish()将起作用,但其余部分将不起作用)。 文档说glFinish应该阻塞线程直到gl命令被执行。 请问有谁能帮助我理解这里发生了什么或提供解决此问题的方法? 为了明确起见,我想连续呈现200帧而不错过任何一帧,并通过写入数字IO端口标记每个帧的刷新(我对此没有问题),所有这些都在Snow Leopard上完成。
1个回答

4
这不是我的专业领域 - 我自己只是一个相当基础的NSOpenGLView用户 - 但根据Mac OpenGL文档,看起来你可能想要使用CVDisplayLink (Q&A1385)。即使那样做行不通,那里的其他内容也应该会有所帮助。

编辑

我只进行了一些基本测试,但看起来只要首先设置正确的OpenGL上下文,然后在每个帧之后交换缓冲区(假设您正在使用双缓冲上下文),就可以实现您想要的内容:

// inside an NSOpenGLView subclass, somewhere outside the usual drawing loop
- (void) drawMultipleFrames
{
    // it might be advisable to also do a [self lockFocus] here,
    // although it seems to work without that in my simple tests

    [[self openGLContext] makeCurrentContext];

    // ... set up common OpenGL state ...

    for ( i = 0; i < LOTS_OF_FRAMES; ++i )
    {
        // ... draw your frame ...

        glFinish();
        glSwapAPPLE();
    }

    // unlockFocus here if locked earlier
}

我之前尝试在每帧结束时使用[[self openGLContext] flushBuffer],这不需要glSwapAPPLE,但不像glFinish那样阻塞,因此可能会导致帧互相覆盖。这似乎可以在其他应用程序中正常工作,在后台运行等,但当然结果可能因人而异。


谢谢,这帮助我理解了一些我正在处理的其他问题。但是在这里,如果可能的话,我想避免基于事件的解决方案(将needsDisplay设置为YES之类的方法不能告诉我一个帧"确切地"何时被显示)。 - undefined
@Ali 嗯,看起来那也可以——参见编辑。反正已经拖延够久了,回到工作状态吧! - undefined
你救了我!其实我不知道这些苹果的GL函数!我把所有的glFinishglFlush都替换成了glFlushRenderAPPLEglFinishRenderAPPLE,并在最后加上了一个glSwapAPPLE,结果完美无缺!谢谢啊。 - undefined
请注意,如果您正在使用一个与垂直同步(vsync)相关的上下文,这并不足够,因为在OpenGL中,交换(swap)不会立即阻塞,而是在下一次交换时才会阻塞。也就是说,您的代码将比显示器落后1帧。您还应该使用cvdisplaylink来等待垂直同步。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接