2016-12-22 63 views
1

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

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

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

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

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

回答

0

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

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

然后,主线程应该检查它是否获得了显示新纹理的请求,以及何时它应该将其绘制到主缓冲区并呈现它。如果你需要以60FPS(或任何其他常量)绘制它,你仍然可以做到这一点,但你会重绘相同的纹理。

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