用AI赚第一桶💰低成本搭建一套AI赚钱工具,源码可二开。 广告
### Android GDI之SurfaceFlinger SurfaceFinger按英文翻译过来就是Surface投递者。SufaceFlinger的构成并不是太复杂,复杂的是他的客户端建构。SufaceFlinger主要功能是: 1) 将Layers (Surfaces) 内容的刷新到屏幕上 2) 维持Layer的Zorder序列,并对Layer最终输出做出裁剪计算。 3) 响应Client要求,创建Layer与客户端的Surface建立连接 4) 接收Client要求,修改Layer属性(输出大小,Alpha等设定) 但是作为投递者的实际意义,我们首先需要知道的是如何投递,投掷物,投递路线,投递目的地。 ### 1  SurfaceFlinger的基本组成框架 [![image](https://box.kancloud.cn/2016-05-05_572b1a2a8abcb.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_1276518584xvSo.gif) SurfaceFlinger管理对象为: mClientsMap:管理客户端与服务端的连接。 ISurface,IsurfaceComposer:AIDL调用接口实例 mLayerMap:服务端的Surface的管理对象。 mCurrentState.layersSortedByZ :以Surface的Z-order序列排列的Layer数组。 graphicPlane 缓冲区输出管理 OpenGL ES:图形计算,图像合成等图形库。 gralloc.xxx.so这是个跟平台相关的图形缓冲区管理器。 pmem Device:提供共享内存,在这里只是在gralloc.xxx.so可见,在上层被gralloc.xxx.so抽象了。 ### 2 SurfaceFinger Client和服务端对象关系图 [[![image](https://box.kancloud.cn/2016-05-05_572b1a2aa243c.gif "image")](http://hi.csdn.net/attachment/201006/14/0_12765192776tBE.gif)](http://hi.csdn.net/attachment/201006/14/0_12765192744dUQ.gif) Client端与SurfaceFlinger连接图: [![image](https://box.kancloud.cn/2016-05-05_572b1a2b32428.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_1276518598A6OZ.gif)  Client对象:一般的在客户端都是通过SurfaceComposerClient来跟SurfaceFlinger打交道。 [![image](https://box.kancloud.cn/2016-05-05_572b1a2b44483.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_1276518601fTft.gif) [![image](https://box.kancloud.cn/2016-05-05_572b1a2b5b4e7.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_1276518603bAHB.gif) ### 3 主要对象说明 #### 3.1 DisplayHardware &FrameBuffer 首先SurfaceFlinger需要操作到屏幕,需要建立一个屏幕硬件缓冲区管理框架。Android在设计支持时,考虑多个屏幕的情况,引入了graphicPlane的概念。在SurfaceFlinger上有一个graphicPlane数组,每一个graphicPlane对象都对应一个DisplayHardware.在当前的Android(2.1)版本的设计中,系统支持一个graphicPlane,所以也就支持一个DisplayHardware。 SurfaceFlinger,Hardware硬件缓冲区的数据结构关系图。 [![image](https://box.kancloud.cn/2016-05-05_572b1a2b713b8.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_1276518606owJM.gif) #### 3.2 Layer [![image](https://box.kancloud.cn/2016-05-05_572b1a2b89104.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_1276518608eft1.gif) method:setBuffer  在SurfaceFlinger端建立显示缓冲区。这里的缓冲区是指的HW性质的,PMEM设备文件映射的内存。 1) layer的绘制 ~~~ void Layer::onDraw(const Region& clip) const {     int index = mFrontBufferIndex;     GLuint textureName = mTextures[index].name; …   drawWithOpenGL(clip, mTextures[index]); } ~~~ #### 3.2 mCurrentState.layersSortedByZ 以Surface的Z-order序列排列的LayerBase数组,该数组是层显示遮挡的依据。在每个层计算自己的可见区域时,从Z-order 顶层开始计算,是考虑到遮挡区域的裁减,自己之前层的可见区域就是自己的不可见区域。而绘制Layer时,则从Z-order底层开始绘制,这个考虑到透明层的叠加。 ### 4 SurfaceFlinger的运行框架 我们从前面的章节<Android Service>的基本原理可以知道,SurfaceFlinger的运行框架存在于:threadLoop,他是SurfaceFlinger的主循环体。SurfaceFlinger在进入主体循环之前会首先运行:SurfaceFlinger::readyToRun()。 #### 4.1 SurfaceFlinger::readyToRun() (1)建立GraphicPanle (2)建立FrameBufferHardware(确定输出目标) 初始化:OpenGL ES 建立兼容的mainSurface.利用eglCreateWindowSurface。 建立OpenGL ES进程上下文。 建立主Surface(OpenGL ES)。 DisplayHardware的Init()@DisplayHardware.cpp函数对OpenGL做了初始化,并创建立主Surface。为什么叫主Surface,因为所有的Layer在绘制时,都需要先绘制在这个主Surface上,最后系统才将主Surface的内容”投掷”到真正的屏幕上。 (3) 主Surface的绑定 1)在DisplayHandware初始完毕后,hw.makeCurrent()将主Surface,OpenGL ES进程上下文绑定到SurfaceFlinger的上下文中, 2)之后所有的SurfaceFlinger进程中使用EGL的所有的操作目的地都是[mSurface@DisplayHardware](#)。 这样,在OpenGL绘制图形时,主Surface被记录在进程的上下文中,所以看不到显示的主Surfce相关参数的传递。下面是Layer-Draw,Hardware.flip的动作示意图: [![image](https://box.kancloud.cn/2016-05-05_572b1a2b9bc43.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_1276518609tWF6.gif) #### 4.2 ThreadLoop [![image](https://box.kancloud.cn/2016-05-05_572b1a2bb19a5.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_12765186106SH3.gif) (1)handleTransaction(…):主要计算每个Layer有无属性修改,如果有修改着内用需要重画。 (2)handlePageFlip() computeVisibleRegions:根据Z-Order序列计算每个Layer的可见区域和被覆盖区域。裁剪输出范围计算- 在生成裁剪区域的时候,根据Z_order依次,每个Layer在计算自己在屏幕的可显示区域时,需要经历如下步骤: 1)以自己的W,H给出自己初始的可见区域 2)减去自己上面窗口所覆盖的区域 [![image](https://box.kancloud.cn/2016-05-05_572b1a2bc3d8d.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_1276518612eyG3.gif) 在绘制时,Layer将根据自己的可将区域做相应的区域数据Copy。 (3)handleRepaint() composeSurfaces(需要刷新区域): 根据每个Layer的可见区域与需要刷新区域的交集区域从Z-Order序列从底部开始绘制到主Surface上。 (4)postFramebuffer() (DisplayHardware)hw.flip(mInvalidRegion); eglSwapBuffers(display,mSurface) :将mSruface投递到屏幕。 ### 5 总结 现在SurfaceFlinger干的事情利用下面的示意图表示出来: [![image](https://box.kancloud.cn/2016-05-05_572b1a2bd7cb1.gif "image") ](http://hi.csdn.net/attachment/201006/14/0_1276518615Bgfw.gif)