SurfaceFlinger是Android multimedia的一个部分,在Android的实现中它是一个service,提供系统范围内的surface composer功能,它能够将各种应用程序的2D、3D surface进行组合。在具体讲SurfaceFlinger之前,我们先来看一下有关显示方面的一些基础知识。
1、原理分析
让我们首先看一下下面的屏幕简略图:
SurfaceFlinger中加入了Overlay hal,只要实现这个Overlay hal可以使用overlay的功能,这个头文件在:/hardware/libhardware/include/harware/Overlay.h,可以使用FB或者V4L2 output来实现,这个可能是我们将来工作的内容。实现Overlay hal以后,使用Overlay接口的sequence就在:/frameworks/base/libs/surfaceflinger/tests/overlays/Overlays.cpp,这个sequnce是很重要的,后面我们会讲到。
不过在实际中我们不一定需要实现Overlay hal,如果了解硬件的话,可以在驱动中直接把这些信息送到OverlayBuffer,而不需要走上层的Android。Fsl现在的Camerapreview就是采用的这种方式,而且我粗略看了r3补丁的内容,应该在opencore的视频播放这块也实现了Overlay。
3、SurfaceFlinger
现在就来看看最复杂的SurfaceFlinger,首先要明确的是SurfaceFlinger只是负责mergeSurface的控制,比如说计算出两个Surface重叠的区域,至于Surface需要显示的内容,则通过skia,opengl和pixflinger来计算。所以我们在介绍SurfaceFlinger之前先忽略里面存储的内容究竟是什么,先弄清楚它对merge的一系列控制的过程,然后再结合2D,3D引擎来看它的处理过程。
3.1、Surface的创建过程
前面提到了每个应用程序可能有一个或者多个Surface,我们需要一些数据结构来存储我们的窗口信息,我们还需要buffer来存储我们的窗口内容, 而且最主要的是我们应该确定一个方案来和SurfaceFlinger来交互这些信息,让我们首先看看下面的Surface创建过程的类图:
为应用程序创建一个Client以后,下面需要做的就是为这个Client分配Surface,Flinger为每个Client提供了8M的空间,包括控制信息和存储内容的buffer。在说创建surface之前首先要理解layer这个概念,回到我们前面看的屏幕简略图,实际上每个窗口就是z轴上的一个layer,layer提供了对窗口控制信息的操作,以及内容的处理(调用opengl或者skia),也就是说SurfaceFlinger只是控制什么时候应该进行这些信息的处理以及处理的过程,所有实际的处理都是在layer中进行的,可以理解为创建一个Surface就是创建一个Layer。不得不说Android这些乱七八糟的名字,让我绕了很久……
创建Layer的过程,首先是由这个应用程序的Client根据应用程序的pid生成一个唯一的layer ID,然后根据大小,位置,格式啊之类的信息创建出Layer。在Layer里面有一个嵌套的Surface类,它主要包含一个ISurfaceFlingerClient::Surface_data_t,包含了这个Surace的统一标识符以及buffer信息等,提供给应用程序使用。最后应用程序会根据返回来的ISurface信息等创建自己的一个Surface。
先大致讲一下Android组合各个窗口的原理:Android实际上是通过计算每一个窗口的可见区域,就是我们在屏幕上可见的窗口区域(用Android的词汇来说就是visibleRegionScreen ),然后将各个窗口的可见区域画到一个主layer的相应部分,最后就拼接成了一个完整的屏幕,然后将主layer输送到FB显示。在将各个窗口可见区域画到主layer过程中涉及到一个硬件实现和一个软件实现的问题,如果是软件实现则通过Opengl重新画图,其中还包括存在透明度的alpha计算;如果实现了copybit hal的话,可以直接将窗口的这部分数据直接拷贝过来,并完成可能的旋转,翻转,以及alhpa计算等。
下面来看看Android组合各个layer并送到FB显示的具体过程:
4.1、handleConsoleEvent
当接收到signal或者singalEvent事件以后,线程就停止等待开始对Client的请求进行处理,第一个步骤是handleConsoleEvent,这个步骤我看了下和/dev/console这个设备有关,它会取得屏幕或者释放屏幕,只有取得屏幕的时候才能够在屏幕上画图。
4.2、handleTransaction
前面提到过,窗口状态的改变只能在一个Transaction中进行。因为窗口状态的改变可能造成本窗口和其他窗口的可见区域变化,所以就必须重新来计算窗口的可见区域。在这个处理子过程中Android会根据标志位来对所有layer进行遍历,一旦发现哪个窗口的状态发生了变化就设置标志位以在将来重新计算这个窗口的可见区域。在完成所有子layer的遍历以后,Android还会根据标志位来处理主layer,举个例子,比如说传感器感应到手机横过来了,会将窗口横向显示,此时就要重新设置主layer的方向。
4.3、handlePageFlip
这里会处理每个窗口surface buffer之间的翻转,根据layer_state_t的swapsate来决定是否要翻转,当swapsate的值是eNextFlipPending是就会翻转。处理完翻转以后它会重新计算每个layer的可见区域,这个重新计算的过程我还没看太明白,但大致是一个这么的过程:
从Z值最大的layer开始计算,也就是说从最上层的layer计算,去掉本身的透明区域和覆盖在它上面的不透明区域,得到的就是这个layer的可见区域。然后这个layer的不透明区域就会累加到不透明覆盖区域,这个layer的可见区域会放入到主layer的可见区域,然后计算下一个layer,直到计算完所有的layer的可见区域。这中间的计算是通过定义在skia中的一种与或非的图形逻辑运算实现的,类似我们数学中的与或非逻辑图。
4.4、handleRepaint
计算出每个layer的可见区域以后,这一步就是将所有可见区域的内容画到主layer的相应部分了,也就是说将各个surface buffer里面相应的内容拷贝到主layer相应的buffer,其中可能还涉及到alpha运算,像素的翻转,旋转等等操作,这里就像我前面说的可以用硬件来实现也可以用软件来实现。在使用软件的opengl做计算的过程中还会用到PixFlinger来做像素的合成,这部分内容我还没时间来细看。
4.5、postFrameBuffer
最后的任务就是翻转主layer的两个buffer,将刚刚写入的内容放入FB内显示了。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!