Ios CaeAglayer的异步渲染

Ios CaeAglayer的异步渲染,ios,asynchronous,opengl-es,uikit,Ios,Asynchronous,Opengl Es,Uikit,我有一个基于OpenGL的渲染管道用于过滤图像,现在我想用它来处理视频 如果管道一端是用于从视频文件获取帧的AVPlayer,另一端是我的预览视图,后面是caeaglayer。渲染本身在另一个线程上异步进行,因为它非常昂贵。该视图连接到一个CADisplayLink,该链接在每次屏幕刷新时触发一个新的异步渲染。当管道渲染到层的renderbuffer中时,我调用presentRenderbuffer:在屏幕上显示它(在渲染线程中)。渲染仍在进行时发生的绘制请求将被忽略 不过,这是可行的,我似乎在

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

如果管道一端是用于从视频文件获取帧的
AVPlayer
,另一端是我的预览视图,后面是
caeaglayer
。渲染本身在另一个线程上异步进行,因为它非常昂贵。该视图连接到一个
CADisplayLink
,该链接在每次屏幕刷新时触发一个新的异步渲染。当管道渲染到层的renderbuffer中时,我调用
presentRenderbuffer:
在屏幕上显示它(在渲染线程中)。渲染仍在进行时发生的绘制请求将被忽略

不过,这是可行的,我似乎在显示刷新时遇到了同步问题。当我将显示链接的
frameInterval
设置为1(每帧调用一次)时,最终得到~2 FPS(实际视图刷新)。如果我将其设置为2(每隔一帧调用一次),我会突然获得15 FPS。将其设置为4会将FPS再次降至2

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


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

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

现在阻止背景线程是没有意义的,因为它预计会很慢,所以它将继续渲染纹理,然后在渲染完成后将纹理发送到主线程(在那里显示缓冲区)并继续绘制到其他纹理。然后重复这个过程

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


现在,为了保持一致,您可能仍然应该执行一些锁定机制。由于后台线程执行缓冲区交换(发送新纹理并开始绘制前一个),因此有一个布尔值
swapLocked
,其中主线程将在开始绘制之前将其设置为
true
,并在完成纹理后将其设置为
false
。现在,如果后台线程已完成绘制,且
交换的
true
则不应继续绘制。在这种情况下,一旦
swapLocked
设置为
false
,则继续交换和图形。您可以重写setter来执行此操作,但请小心在后台线程上继续此过程,因为setter很可能在主线程上被调用。

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

现在阻止背景线程是没有意义的,因为它预计会很慢,所以它将继续渲染纹理,然后在渲染完成后将纹理发送到主线程(在那里显示缓冲区)并继续绘制到其他纹理。然后重复这个过程

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

现在,为了保持一致,您可能仍然应该执行一些锁定机制。由于后台线程执行缓冲区交换(发送新纹理并开始绘制前一个),因此有一个布尔值
swapLocked
,其中主线程将在开始绘制之前将其设置为
true
,并在完成纹理后将其设置为
false
。现在,如果后台线程已完成绘制,且
交换的
true
则不应继续绘制。在这种情况下,一旦
swapLocked
设置为
false
,则继续交换和图形。您可以重写setter来实现这一点,但要小心在后台线程上继续该过程,因为setter很可能在主线程上被调用