异步渲染到CAEAGLLayer

时间:2016-12-22 13:16:31

标签: ios asynchronous opengl-es uikit

我有一个基于OpenGL的渲染管道来过滤图像,我现在也想用它来处理视频。

如果管道是AVPlayer用于从视频文件中获取帧,那么另一端是我的预览视图,由CAEAGLLayer支持。渲染本身在不同的线程上发生异步,因为它非常昂贵。视图挂钩到CADisplayLink,在每次屏幕刷新时触发新的异步呈现。当管道完成渲染到图层的渲染缓冲区时,我正在调用presentRenderbuffer:在屏幕上显示它(在渲染线程中)。在渲染仍在进行时绘制请求将被忽略。

这很有效 - 但是,我似乎遇到了显示刷新的同步问题。当我将显示链接的frameInterval设置为1(每帧调用)时,我最终得到~2 FPS(实际视图刷新)。如果我将它设置为2(每隔一帧调用一次),我突然得到15 FPS。将其设置为4将FPS再次降低到2。

我的猜测是,对presentRenderbuffer:的异步调用发生在运行循环中的“错误时刻”,系统会忽略或延迟。

现在我想知道在视图中显示异步渲染结果的最佳做法是什么。我能找到的所有示例和文档只描述了单线程的情况。

1 个答案:

答案 0 :(得分:0)

在这些情况下,最好使用双缓冲,在您的情况下是2个纹理。视频的渲染应该在具有附加纹理的FBO(帧缓冲对象)上完成。由于绘图是在一个单独的线程上,我建议你在主上下文中创建2个纹理,主线程然后在另一个线程上创建一个共享上下文,现在可以访问2个线程。

现在没有意义阻止后台线程,因为它预计会很慢,所以它会做的是继续呈现纹理然后一旦完成将纹理发送到主线程(你呈现缓冲区)并继续绘制到其他纹理。然后重复该过程。

然后主线程应该检查它是否有请求显示新纹理,当它执行时它应该将它绘制到主缓冲区并显示它。如果你需要以60FPS(或任何其他常数)绘制它,你仍然可以这样做,但你将重绘相同的纹理。

现在只是站在同一侧你应该仍然可以做一些锁定机制。由于后台线程执行缓冲区交换(发送新纹理并开始绘制到前一个纹理),因此有一个布尔值swapLocked,其中主线程将其设置为true它开始绘制并在完成纹理后将其设置为false。现在,如果后台线程已完成绘图且swapLockedtrue,则不应继续绘制。在这种情况下,在swapLocked设置为false后继续交换和绘图。您可以覆盖setter来执行此操作,但要小心在后台线程上继续该过程,因为很可能在主线程上调用setter。