0%

OpenGL在Android系统下的工作原理

对于OpenGL新手来说,在Android下使用OpenGL进行视频、图像渲染,最最重要的是要清楚Android系统下它的显示系统是如何工作的。只有将其搞清楚,我们才能更好的、更正确的使用OpenGL对视频/图片进行渲染,才能更高效的进行各种特效处理。

那么今天,我们就来聊聊Android系统下的显示系统,看看它到底是如何工作的!

Android的显示系统

在开始之前,我们先通过一张图从整体上一窥Android的显示系统。

首先我们来看看这张图中都包含那些组件,我们按照从左到右的顺序进行介绍:

  • Camera,它是一个硬件设备,用于采集视频帧。

  • Surface,它是一个帧缓冲区管理器,它里边管理着一个BufferQueue,而BufferQueue中存放着是一幅幅图像。

  • BufferQueue,它是一个存放图象的队列,它里边的每个元素都存放着一幅图像。

  • SurfaceTexture,一方面它可以作为BufferQueue的消费者,当BufferQueue中有数据时,它可以从中取出数据;另一方面它可以将图像转成纹理交由OpenGL处理。

  • OpenGLES,它利用GPU对图像进行加速渲染或对图像做各种特效处理。

  • WindowManager,用于管理Window。

  • Window,它是一个抽象的概念,它表示屏幕上的一个矩形区域,用于显示一个应用程序的界面。

  • 每个Window中管理着1到多个View,每个View就是应用程序中的一个页面。

  • SurfaceView,它是View的一个子类,每个SurfaceView都有自己的Surface用于存放要显示的数据。由于它并没有与父类共用同一个Surface,所以它的内容是可以浮在父类View之上的。

  • TextureView,它也是View的一个子类,它没有自己的Surface,而是与父类共用同一个Surface。它的好处是当屏幕发生旋转时,父类View可以正常旋转,而它父类共用Surface的TextureView所绘制的内容也可以正常旋转,不用单独处理了。而SurfaceView则需要开发者自己处理旋转问题。

  • GLSurfaceView是SurfaceView的子类,它在SurfaceView的基础上开了一个新的线程专门处理OpenGL相关的事儿。比如建立OpenGLES上下文环境,调用OpenGLES API进行渲染等。

  • GLSurfaceView.Render类,它用于调用OpenGLES API进行渲染,GLSurfaceView的渲染线程周期性的刷新视频帧,每次刷新的时候就会调用GLSurfaceView.Render类的Draw()方法。

  • SurfaceHolder是GLSurfaceView的辅助类,用于帮助GLSurfaceView管理Surface。

  • SurfaceControl是SurfaceHolder的辅助类,用于控制Surface。

  • SurfaceFlinger,它是Android上的一个后台服务,同时它还是Layer的管理器,用于将多个 Layer 合成到屏幕上一起显示。

  • Layer,是SurfaceView中Surface的消费者,用于从Surface中消费数据。

  • Hardware,它是一个硬件抽象层,它可以让 SurfaceFlinger 将一些合成工作委托给显示子系统的硬件。

  • Screen,它是最终的显示设备,如手机或平板电脑的屏幕。

这样我就将上图中所以模块的作用向你介绍清楚了。接下来咱们来看一下从Camera中采集的视频帧是如何一步步在Android系统中流转,并最终在屏幕上显示出来的。

从Camera到显示屏

首先,当 Camera 采集到一帧数据后,它会直接将这个数据放入到 Surface 中。如前面所述,这个 Surface 就是一个缓冲区队列的管理者,它的作用是在不同的线程之间传递图像数据,它会将视频帧的句柄放入它所管理的 BufferQueue 中,等待消费者来取走。

之后,当我们想在Android 系统中使用OpenGL渲染视频帧时,我们会在创建SurfaceView/GLSurfaceView时构造一个SurfaceTexutre对象,并将SurfaceTexture交给Surface,这样Surface就会在BufferQueue中有数据时通知SurfaceTexture取走。

另外,SurfaceTexture也像是一座桥,它一头连着Surface,而另一头连接OpenGL。当它从 BufferQueue 中取出视频帧数据后,会将其转换为 GLES 纹理交由OpenGL处理。

那么,当SurfaceTexture将图像转成纹理交给OpenGL后,OpenGL是否会马上处理呢?实际上它有两种模式:一种是直接进行处理,这种更高效一些,它的工作方式类似于事件处理;另一种则是循环处理,即每隔一段时间就处理一次。

对于立即处理的方式大家都很好理解,这里我就不赘述了。对于循环处理模式你可以把它想像成一台发动机,它会按照屏幕的刷新帧率不断的调用Render类的Draw()方法。而在Draw()方法中会调用 OpenGLES 的API,触发Shader程序,最终利用Shader程序将图像渲染出来,而在Shader程序中,我们就可以为视频帧纹理添加各种滤镜特效了。

最终渲染的结果会被输出到 GLSurfaceView所管理的 Surface 上,等待消费者来取走。而该Surface的消费者就是Layer(这里我们要注意,图中有两个Surface,其中一个用于Camera与应用程序之间传递图像数据,而另一个用于应用程序与SurfaceFlinger服务之间传递数据,而这里指的Surface是指第二个Surface)。每一个View就会在Surface Flinger服务中有一个与之对应的Layer。

SurfaceFlinger是Android系统的一个后台服务(一个单独的进程)。它会定期的将要显示的所有Layer合并到一起(这步操作类似于Adobe PS中的图层的概念),比如在同一个应用中,有多个View要显示,此时它会算法,如果上面的View的Layer是否盖住了下面的View的Layer?如果是,那么就只显示最上层的Layer。但如果是另一种情况,上层Layer是一个小窗口,没有将下面的View全部盖住,那么SurfaceFlinger就会将它们合并成一张图送给Hardware。

而Hardware会驱动硬件层将显示内容投到Screen上,这样我们就看到了最终的结果。

那么,在这个过程中OpenGL具体是如何工作的呢?关于这方面的内容我会在下一篇文章中向你做详细的介绍。

小结

在我看来,想在Android系统下使用好OpenGL,那你必须要先将Android显示系统的工作原理搞清楚,这样我们就有了一张完整的地图,而接下来的学习就是拿着一个“放大镜”,哪里不会就去哪里看一看,直到将整个地图的各个节细全部看清。

所以,我建议大家一定经常把这张图拿出来看一看,让自己了解自己现在自己学到哪个阶段了,下一个阶该学习什么。

参考资料

系统玩转OpenGL+AI,实现各种酷炫视频特效

欢迎关注我的其它发布渠道