浅析GPUImage的设计思想

2017-12-07  本文已影响212人  码农苍耳

在移动端图片处理时,往往因为大量的计算导致需要较长的时间,为了充分利用设备的潜能,所以产生了利用GPU来处理计算的方案。其中最有名的开源方案就是GPUImage

结构

GPUImage的设计思路参考了流式的结构,所有东西都被概括为input或者output,其中最重要的filter则既是input也是output。这样设计统一了整个流程,但让整个结构变的更加死板和复杂。大概的流程如下:

Image >> Input >> Filter_1 >> Filter_2 >> Filter_x >> Output

当存在多个Filter的时候,整个结构上就会变的比较难以理解,所以个人认为,需要分开的结构还是分开比较好:

Image >>   Dispatch   >> Output
            /   \
           /     \
    Filter_1 ... Filter_x

性能优化

GPUImage自身在设计的时候就考虑到了优化,所以有些时候你可能会感觉某些结构上有些奇怪。

比如GPU内存申请基本上是在输入端就创建好了,在Filter中是不会新申请内存的,都是重用了开始就申请好的内存,除非改变了画布大小。

Filter最好进行重用,因为OpenGL es首先需要利用CPU将GLSL编译为GPU可执行的代码,最好的情况是能够重用这部分已经编译完成的代码。

当我们利用GPUImage来处理图片时,一般不会有什么性能问题,但是如果我们利用他来处理视频时,就需要考虑到极限下的性能问题。我们来模拟下多个Filter情况下的GPU处理1帧的情景:

Image >> Input >> Filter_1 >> Filter_x >> Output
                   /    \
        Prepare(CPU) >> Process(GPU)

可以看到每个Filter之间是同步执行的,所以无法很好的利用CPU多线程的能力。理想状况下应该是这样:

Image >> Input >> Filter_1     ...  Filter_x
                     |                  |
                Prepare(CPU)    >>  Prepare(CPU)
                     |                  |
                Progress(GPU)   >>  Processor(GPU)  >>  Output

这样就可以将串行执行改为CPU和GPU并发执行,不过GPUImage目前无法改造为这样的结构。

OpenGL es

目前iOS平台支持的GPU平台编码主要有2种方式,一种是OpenGL es,另一种就是Metal。按照官方说法,Metal的性能会比OpenGL更好,好像是因为在编译期就进行了一次初期编码,将代码转化为一种类似于bitcode一样的中间码。

OpenGL的基本流程如下:

CPU: 创建FrameBuffer + GLSL
                | draw
GPU:         main()
                | readPixel
CPU        read to RAM

GLSL

想要了解GPUImage就必须先学会使用OpenGL,那么就离不开学习GLSL,如果你使用CIImage,你也可能会需要KISL,是GLSL的一种子集。

GLSL并不复杂,是一种非常类似于C语言的DSL,但是要与程序进行交互则会变得麻烦。

总结

要实现自己的Filter,则首先需要学习OpenGL以及GLSL,这是一个比较大的障碍点。

如果仅仅是为了图片处理,那么GPUImage已经足够了。如果你需要高分辨率高帧率的视频渲染,GPUImage可能就满足不了你,优化思路是并发和利用空间去换取时间。

上一篇下一篇

猜你喜欢

热点阅读