我有一个基于OpenGL的渲染管道,用于过滤图像,现在我也想用它来处理视频。
在一端,如果管道是一个从视频文件中获取帧的AVPlayer,另一端是我的预览视图,由CAEAGLLayer支持。渲染本身是在不同的线程上异步进行的,因为它的开销很大。视图被挂接到一个CADisplayLink,该a在每次屏幕刷新时触发新的异步渲染。当管道渲染到层的renderbuffer中时,我调用presentRenderbuffer:将其显示在屏幕上(在渲染线程中)。在渲染仍在进行中时发生的绘制请求将被忽略。
这是可行的--但是,我似乎在显示刷新时遇到了同步问题。当我将显示链接的frameInterval设置为1(每帧调用一次)时,我最终得到了~2FPS(实际视图刷新)。如果我将其设置为2(每隔一帧调用一次),我会突然获得15FPS。将其设置为4会再次将FPS降至2。
我的猜测是,对presentRenderbuffer:的异步调用发生在运行循环中的“错误时刻”,要么被系统忽略,要么被延迟。
现在我想知道在视图中显示异步渲染结果的最佳实践是什么。我能找到的所有示例和文档都只能描述单线程的情况。
发布于 2016-12-22 21:35:05
在这些情况下,最好使用双缓冲,在您的情况下是2个纹理。视频的渲染应该在附加了纹理的FBO (帧缓冲区对象)上完成。由于绘图是在一个单独的线程上,我建议你在主线程上创建两个纹理,然后在另一个线程上创建一个共享上下文,现在可以访问这两个线程。
现在阻塞后台线程是没有意义的,因为它预计会很慢,所以它将做的是继续渲染到纹理,然后一旦完成,将纹理发送到主线程(在那里呈现缓冲区),并继续绘制到另一个纹理。
然后主线程应该检查它是否收到了显示新纹理的请求,当它收到请求时,它应该将它绘制到主缓冲区并呈现它。如果你需要以60FPS (或任何其他常量)来绘制它,你仍然可以这样做,但你将重新绘制相同的纹理。
现在,为了站在同一方,你可能仍然应该做一些锁定机制。由于后台线程执行缓冲区交换(发送新纹理并开始绘制前一个纹理),因此有一个布尔值swapLocked是有意义的,其中主线程会在开始绘制之前将其设置为true,并在处理完纹理后将其设置为false。现在,如果后台线程完成了绘制,并且swapLocked为true,那么它应该不会继续绘制。在这种情况下,一旦swapLocked设置为false,就继续交换和绘制。您可以重写setter来执行此操作,但要小心在后台线程上继续该进程,因为setter很可能会在主线程上被调用。
https://stackoverflow.com/questions/41284094
复制相似问题