在iOS中将RGB像素数据高效地复制到屏幕上

我们的产品包含一种软件图像解码器,它主要产生需要快速复制屏幕(我们在iOS上运行)的全帧像素数据。

目前我们使用的是CGBitmapContextCreate,我们直接访问内存缓冲区,然后为每一帧调用CGBitmapContextCreateImage,然后将该位图绘制到屏幕上。 这对于在iPad的视网膜显示器上进行全屏刷新的速度太慢了,但是对于非视网膜设备来说也是可以的。

我们已经尝试了各种基于OpenGL ES的方法,包括使用glTexImage2D和glTexSubImage2D(本质上是渲染纹理),但CPU使用率仍然很高,我们无法获得超过30 FPS的全屏刷新在iPad 3上。问题是,在30 FPS下,CPU使用率接近于100%,只是将像素复制到屏幕上,这意味着我们没有太多的工作来处理我们自己在CPU上的渲染。

我们愿意使用OpenGL或任何可以提供最佳性能的iOS API。 像素数据被格式化为每像素32位的RGBA数据,但我们有一些灵活性…

有什么build议么?

所以坏消息是你遇到了一个很难的问题。 我已经在这个特定的领域做了大量的研究,目前唯一的方法就是使用h.264解码器来实现将全屏大小为2x的帧缓冲区。 一旦将图像数据解码为实际的内存(查看GPUImage),就可以使用OpenGL完成一些不错的技巧。 但是,最大的问题不是如何将像素从实时存储器移动到屏幕上。 真正的问题是如何将像素从磁盘上的编码forms移动到实时内存中。 可以使用文件映射内存来保存磁盘上的像素,但是IO子系统速度不够快,无法将足够的页面交换出来,以便能够从映射的内存中传输2个全屏大小的图像。 这个用于1x全屏大小,但现在2倍大小的屏幕实际上是4倍的内存和硬件无法跟上。 您也可以尝试以更加压缩的格式(例如PNG)在磁盘上存储帧。 但是,然后解码压缩格式改变了从IO绑定到CPU绑定的问题,你仍然坚持。 请查看我的博客文章opengl_write_texture_cache ,了解完整的源代码和时间结果,我发现这种方法。 如果你有一个非常特定的格式,你可以限制input图像数据(比如一个8位表),那么你可以使用GPU通过着色器将8位数据作为32BPP像素进行传输,如下例所示:xcode project opengl_color_cycle 。 但是,我的build议是考虑如何使用h.264解码器,因为它实际上能够解码硬件中的大量数据,而且没有其他方法可能会为您提供所需的结果。

CoreVideo很可能是你应该看的框架。 使用OpenGL和CoreGraphics方法,您将受到从主存储器向GPU存储器移动位图数据的成本的困扰。 这个成本也存在于桌面上,但在iPhone上尤其痛苦。

在这种情况下,OpenGL不会为CoreGraphics提高速度,因为瓶颈是纹理数据副本。 OpenGL将为你提供一个更高效的渲染pipe道,但是破坏已经由纹理复制完成了。

所以CoreVideo是要走的路。 就我所了解的框架而言,它解决了你遇到的问题。

然后,pbuffer或FBO可以作为一个纹理贴图用于OpenGL ES的进一步渲染。 这被称为渲染到纹理或RTT。 它在EGL中更快的searchpbuffer或者FBO

经过几年以及我遇到这种需求的几种不同的情况,我决定为iOS实现一个基本的“ 像素查看器 ”视图。 它支持高度优化的各种格式的像素缓冲区显示,包括32-bpp RGBA,24-bpp RGB和几种YpCbCr格式。

它还支持所有的UIViewContentMode *进行智能缩放,缩放以适应/填充等。

该代码经过高度优化(使用OpenGL),即使在iPhone 5或原版iPad Air等较旧的iOS设备上也能获得优异的性能。 在这些设备上,除了24bpp格式外,所有像素格式都能达到60fps,达到30-50fps(我通常通过在设备的原始分辨率下显示像素缓冲区来进行基准testing),所以显然,iPad必须推动比iPhone更多的像素5)。

请检查出EEPixelViewer 。