Android Display System --- Surface Flinger

     SurfaceFlinger Android multimedia 的一个部分,在Android 的实现中它是一个service ,提供系统 范围内的surface composer功能,它能够将各种应用 程序的2D 、3D surface 进行组合。在具体讲SurfaceFlinger 之前,我们先来看一下有关显示方面的一些基础知识 

 

1 原理 分析

让我们首先看一下下面的屏幕简略图:

 

 

 

每个应用程序可能对应着一个或者多个图形界面,而每个界面我们就称之为一个surface ,或者说是window ,在上面的图中我们能看到4 个surface ,一个是home 界面,还有就是红、绿、蓝分别代表的3 个surface ,而两个button 实际是home surface 里面的内容。在这里我们能看到我们进行图形显示所需要解决 的问题:

    a 、首先每个surface 在屏幕上有它的位置,以及大小,然后每个surface 里面还有要显示的内容,内容,大小,位置 这些元素 在我们改变应用程序的时候都可能会改变,改变时应该如何处理 

b 、然后就各个surface 之间可能有重叠,比如说在上面的简略图中,绿色覆盖了蓝色,而红色又覆盖了绿色和蓝色以及下面的home,而且还具有一定透明度。这种层之间的关系应该如何描述?      

我们首先来看第二个问题,我们可以想象在屏幕平面的垂直方向还有一个Z 轴,所有的surface 根据在Z 轴上的坐标来确定前后,这样就可以描述各个surface 之间的上下覆盖关系了,而这个在Z 轴上的顺序,图形上有个专业术语叫Z-order 。  

    对于第一个问题,我们需要一个结构来记录应用程序界面的位置,大小,以及一个buffer 来记录需要显示的内容,所以这就是我们surface 的概念,surface 实际我们可以把它理解成一个容器,这个容器记录着应用程序界面的控制信息,比如说大小啊,位置啊,而它还有buffer 来专门存储需要显示的内容。

    在这里还存在一个问题,那就是当存在图形重合的时候应该如何处理呢,而且可能有些surface 还带有透明信息,这里就是我们SurfaceFlinger 需要解决问题,它要把各个surface 组合(compose/merge) 成一个main Surface ,最后将Main Surface 的内容发送给FB/V4l2 Output ,这样屏幕上就能看到我们想要的效果。

    在实际中对这些Surface 进行merge 可以采用两种方式,一种就是采用软件的形式来merge ,还一种就是采用硬件的方式,软件的方式就是我们的SurfaceFlinger ,而硬件的方式就是Overlay 。

 

2 OverLay

     因为硬件merge 内容相对简单,我们首先来看overlay  Overlay 实现的方式有很多,但都需要硬件的支持。以IMX51 为例子,当IPU向内核申请FB 的时候它会申请3 个FB ,一个是主屏的,还一个是副屏的,还一个就是Overlay 的。 简单地来说,Overlay就是我们将硬件所能接受的格式数据 和控制信息送到这个Overlay FrameBuffer,由硬件驱动来负责merge Overlay buffer和主屏buffer中的内容。

    一般来说现在的硬件都只支持一个Overlay,主要用在视频播放以及camera preview上,因为视频内容的不断变化用硬件Merge比用软件Merge要有效率得多,下面就是使用Overlay和不使用Overlay的过程:

 

    

 

    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,如果了解硬件的话,可以在驱动中直接把这些信息送到Overlay Buffer,而不需要走上层的Android。Fsl现在的Camera preview就是采用的这种方式,而且我粗略看了r3补丁的内容,应该在opencore的视频播放这块也实现了Overlay。

 

3、SurfaceFlinger

     现 在就来看看最复杂的SurfaceFlinger,首先要明确的是SurfaceFlinger只是负责merge Surface的控制,比如说计算出两个Surface重叠的区域,至于Surface需要显示的内容,则通过skia,opengl和 pixflinger来计算。 所以我们在介绍SurfaceFlinger 之前先忽略里面存储的内容究竟是什么,先弄清楚它对merge 的一系列控制的过程,然后再结合2D ,3D 引擎来看它的处理过程。

 

3.1 Surface 的创建过程

    前面提到了每个应用程序可能有一个或者多个Surface , 我们需要一些数据结构来存储我们的窗口信息,我们还需要buffer 来存储我们的窗口内容, 而且最主要的是我们应该确定一个方案 来和SurfaceFlinger 来交互这些信息,让我们首先看看下面的Surface 创建过程的类图 

 

 

IBinder 左边的就是客户端部分,也就是需要窗口显示的应用程序,而右边就是我们的Surface Flinger service 。 创建一个surface 分为两个过程,一个是在SurfaceFlinger 这边为每个应用程序(Client) 创建一个管理 结构,另一个就是创建存储内容的buffer ,以及在这个buffer 上的一系列画图之类的操作。

因为SurfaceFlinger 要管理多个应用程序的多个窗口界面,为了进行管理它提供了一个Client 类,每个来请求服务的应用程序就对应了一个Client 。因为surface 是在SurfaceFlinger 创建的,必须返回一个结构让应用程序知道自己申请的surface 信息,因此SurfaceFlinger 将Client 创建的控制结构per_client_cblk_t 经过BClient 的封装以后返回给SurfaceComposerClient ,并向应用程序提供了一组创建和销毁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 提供了 4 种类型的 layer 供选择,每个 layer 对应一种类型的窗口,并对应这种窗口相应的操作: Layer  LayerBlur LayerBuffer  LayerDim 。不得不说再说 Android 起的乱七八糟的名字, LayerBuffer 很容易让人理解成是 Layer  Buffer ,它实际上是一种 Layer 类型。各个 Layer 的效果大家可以参考 Surface.java 里面的描述:/frameworks/base/core/java/android/view/surface.java 。这里要重点说一下两种 Layer ,一个是 Layer (norm layer) ,另一个是LayerBuffer 

Norm Layer  Android 种使用最多的一种 Layer ,一般的应用程序在创建 surface 的时候都是采用的这样的 layer ,了解 Normal Layer 可以让我们知道 Android 进行 display 过程中的一些基础原理。 Normal Layer 为每个 Surface 分配两个 buffer  front buffer  back buffer ,这个前后是相对的概念,他们是可以进行 Flip 的。 Front buffer 用于 SurfaceFlinger 进行显示,而 Back buffer 用于应用程序进行画图,当 Back buffer 填满数据 (dirty) 以后,就会 flip  back buffer 就变成了 front buffer 用于显示,而 front buffer 就变成了 back buffer 用来画图,这两个 buffer 的大小是根据 surface 的大小格式动态变化的。这个动态变化的实现我没仔细看,可以参照  /frameworks/base/lib/surfaceflinger/layer.cpp 中的 setbuffers() 

两个 buffer flip 的方式是 Android display 中的一个重要实现方式,不只是每个 Surface 这么实现,最后写入 FB  main surface 也是采用的这种方式。

LayerBuffer 也是将来必定会用到的一个 Layer ,个人觉得也是最复杂的一个 layer ,它不具备 render buffer ,主要用在 camera preview / video playback 上。它提供了两种实现方式,一种就是 post buffer ,另外一种就是我们前面提到的 overlay  Overlay的接口实际上就是在这个 layer 上实现的。不管是 overlay 还是 post buffer 都是指这个 layer 的数据来源自其他地方,只是 post buffer 是通过软件的方式最后还是将这个 layer merge 主的 FB ,而 overlay 则是通过硬件 merge 的方式来实现。与这个 layer 紧密联系在一起的是 ISurface 这个接口,通过它来注册数据来源,下面我举个例子来说明这两种方式的使用方法:

 

前面几个步骤是通用的:

 

// 要使用 Surfaceflinger 的服务必须先创建一个 client

sp client = new SurfaceComposerClient();

// 然后向 Surfaceflinger 申请一个 Surface  surface 类型为 PushBuffers

sp surface = client->createSurface(getpid(), 0, 320, 240,

            PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);

// 然后取得 ISurface 这个接口, getISurface() 这个函数的调用时具有权限限制的,必须在 Surface.h 中打开:/framewoks/base/include/ui/Surface.h

sp isurface = Test::getISurface(surface);

 

//overlay 方式下就创建 overlay ,然后就可以使用 overlay 的接口了

sp ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);

sp verlay = new Overlay(ref);

 

//post buffer 方式下,首先要创建一个 buffer ,然后将 buffer 注册到 ISurface 

ISurface::BufferHeap buffers(w, h, w, h,

                                          PIXEL_FORMAT_YCbCr_420_SP,

                                         transform,

                                         0,

                                         mHardware->getPreviewHeap());

mSurface->registerBuffers(buffers);