分享

Android4.4深入浅出之SurfaceFlinger总体结构

 Elaine个人小馆 2017-03-06
         

Android4.4 GUI系统框架之SurfaceFlinger

一.             Android GUI框架:

SurfaceFlinger:每当用户程序刷新UI的时候,会中介BufferQueue申请一个bufferdequeueBuffer),然后把UI的信息填入,丢给SurfaceFlingerSurfaceFlinger通过计算多重计算合成visibleRegion之后,丢给openGL层处理,处理之后送到显示器display上显示。

    根据整个Android系统的GUI设计理念,我们不难猜想到至少需要两种本地窗口:

  面向管理者(SurfaceFlinger)

既然SurfaceFlinger扮演了系统中所有UI界面的管理者,那么它无可厚非地需要直接或间接地持有本地窗口,这个窗口就是FramebufferNativeWindow

  面向应用程序

这类窗口是Surface(这里和以前版本出入比较大,之前的版本本地窗口是SurfaceTextureClient

第二种窗口是能直接显示在终端屏幕上的——它使用了帧缓冲区,而第一种Window实际上是从内存缓冲区分配的空间。当系统中存在多个应用程序时,这能保证它们都可以获得一个本地窗口,并且这些窗口最终也能显示到屏幕上——SurfaceFlinger会收集所有程序的显示需求,对它们做统一的图像混合操作。

二.             SurfaceFlinger和BufferQueue

一个UI完全显示到diplay的过程,SurfaceFlinger扮演着重要的角色但是它的职责是“Flinger”,即把系统中所有应用程序的最终的绘图结果进行混合,然后统一显示到物理屏幕上,而其他方面比如各个程序的绘画过程,就由其他东西来担任了。这个光荣的任务自然而然地落在了BufferQueue的肩膀上,它是每个应用程序一对一的辅导老师,指导着UI程序的画板申请作画流程等一系列细节。下面的图描述了这三者的关系:

 

虽说是三者的关系,但是他们所属的层却只有两个,app属于Java层,BufferQueue/SurfaceFlinger属于native层。也就是说BufferQueue也是隶属SurfaceFlinger,所有工作围绕SurfaceFlinger展开。

这里IGraphicBufferProducer就是appBufferQueue重要桥梁,GraphicBufferProducer承担着单个应用进程中的UI显示需求,与BufferQueue打交道的就是它。它的工作流程如下:

 

 

BpGraphicBufferProducerGraphicBufferProducer在客户端这边的代理对象,负责和SF交互,GraphicBufferProducer通过gbpIGraphicBufferProducer类对象)向BufferQueue获取buffer,然后进行填充UI信息,当填充完毕会通知SFSF知道后就对该Buffer进行下一步操作。典型的生产-消费者模式。

接下来具体说明客户端(producer)和服务端SurfaceFlingerconsumer)工作的模式:

     首先这里的buffer是共享缓冲区,故肯定会涉及到互斥锁,所以buffer的状态也会有多种,一般的buffer大致会经过FREE->DEQUEUED->QUEUED->ACQUIRED->FREE这个流程,如右图:   

  BufferQueue

可以认为BufferQueue是一个服务中心,其它两个owner必须要通过它来管理buffer。比如说当producer想要获取一个buffer时,它不能越过BufferQueue直接与consumer进行联系,反之亦然。

  Producer

生产者就是填充”buffer空间的人,通常情况下当然就是应用程序。因为应用程序不断地刷新UI,从而将产生的显示数据源源不断地写到buffer中。当Producer需要使用一块buffer时,它首先会向中介BufferQueue发起dequeue申请,然后才能对指定的缓冲区进行操作。这种情况下buffer就属于producer一个人的了,它可以对buffer进行任何必要的操作,而其它owner此刻绝不能擅自插手。

当生产者认为一块buffer已经写入完成后,它进一步调用BufferQueuequeue。从字面上看这个函数是入列的意思,形象地表达了buffer此时的操作——buffer归还到BufferQueue的队列中。一旦queue成功后,owner也就随之改变为BufferQueue

  Consumer

消费者是与生产者相对应的,它的操作同样受到BufferQueue的管控。当一块buffer已经就绪后,Consumer就可以开始工作了。这里需要特别留意的是,从各个对象所扮演的角色来看,BufferQueue是中介机构,属于服务提供方;Producer属于buffer内容的产出方,它对缓冲区的操作是一个主动的过程;反之,Consumerbuffer的处理则是被动的、等待式——它必须要等到一块buffer填充完成后才能做工作。在这样的模型下,我们怎么保证Consumer可以及时的处理buffer呢?换句话说,当一块buffer数据ready后,应该怎么告知Consumer来操作呢?

仔细观察的话,可以看到BufferQueue里还同时提供了一个特别的类,名称为ProxyConsumerListener,其中的函数接口包括:

  1. classProxyConsumerListener : public BnConsumerListener {  
  2.   
  3. public:       
  4.   
  5.  //省略构造函数  
  6.   
  7.         virtual void onFrameAvailable();/*当一块buffer可以被消费时,这个函数会被调用,特别注意此时没有共享锁的保护*/  
  8.   
  9.         virtual voidonBuffersReleased();/*BufferQueue通知consumer它已经释放其slot中的一个或多个 GraphicBuffer引用*/  
  10.   
  11.     private:  
  12.   
  13.    wpmConsumerListener;  
  14.   
  15. }  


 

 这样子就很清楚了,当有一帧数据准备就绪后,BufferQueue就会调用onFrameAvailable()来通知Consumer进行消费。

BufferQueueSurfaceFlinger之间的通信模式如下:

也是有一对BpGraphicBufferConsumer/BnGraphicBufferConsumer支持他们之间的信息传输。

三.             具体分析BufferQueue

首先说明一下BufferQueue的类关系:

下面是BufferQueue中的核心函数分析:

核心成员函数

说明

setBufferCount

setBufferCount updates the  number of available buffer slots.

requestBuffer

requestBuffer returns the  GraphicBuffer for slot N.

dequeueBuffer

dequeueBuffer gets the next  buffer slot index for the producer to use.

queueBuffer

queueBuffer returns a filled  buffer to the BufferQueue.

cancelBuffer

cancelBuffer returns a  dequeued buffer to the BufferQueue

acquireBuffer

acquireBuffer attempts to  acquire ownership of the next pending buffer BufferQueue.

releaseBuffer

releaseBuffer releases a  buffer slot from the consumer back to the BufferQueue.

 

BufferQueue是IGraphicBufferProducerIGraphicBufferConsumer的具体实现,用户在请求和SurfaceFlinger连接的过程中会请求SF创建一个LayerIGraphicBufferProducer就是在这个过程中获取一个BufferQueue对象,又转化成IGraphicBufferProducer类对象,是为了进一步和BufferQueue进行交互,下面是关键代码:

 

  1. status_t SurfaceFlinger::createNormalLayer(constsp& client,  
  2.   
  3.         const String8& name, uint32_t w,uint32_t h, uint32_t flags, PixelFormat& format,  
  4.   
  5.         sp* handle, sp*gbpsp* outLayer)  
  6.   
  7. {  
  8.   
  9.     switch (format) {  
  10.   
  11.     case PIXEL_FORMAT_TRANSPARENT:  
  12.   
  13.     case PIXEL_FORMAT_TRANSLUCENT:  
  14.   
  15.         format = PIXEL_FORMAT_RGBA_8888;  
  16.   
  17.         break;  
  18.   
  19.     case PIXEL_FORMAT_OPAQUE:  
  20.   
  21.     }  
  22.   
  23.    
  24.   
  25. #ifdefNO_RGBX_8888  
  26.   
  27.     if (format == PIXEL_FORMAT_RGBX_8888)  
  28.   
  29.         format = PIXEL_FORMAT_RGBA_8888;  
  30.   
  31. #endif  
  32.   
  33.    
  34.   
  35.     *outLayer = new Layer(this, client, name,w, h, flags);  
  36.   
  37.     status_t err =(*outLayer)->setBuffers(w, h, format, flags);  
  38.   
  39.     if (err == NO_ERROR) {  
  40.   
  41.         *handle = (*outLayer)->getHandle();  
  42.   
  43.         *gbp =(*outLayer)->getBufferQueue();  
  44.     }  
  45.   
  46.    
  47.   
  48.     ALOGE_IF(err, 'createNormalLayer()failed (%s)', strerror(-err));  
  49.   
  50.     return err;  
  51.   
  52. }  


 

下面是getBufferQueue的实现,很简单,获取BufferQueue对象:

  1. spLayer::getBufferQueue() const {  
  2.   
  3.     return mBufferQueue;  
  4.   
  5. }  


 

IGraphicBufferProducer是个接口类,它的实现必然在子类BpGraphicBufferProducer中实现,我们来看下这个类:

 

  1. classBpGraphicBufferProducer : public BpInterface  
  2.   
  3. {  
  4.   
  5. public:  
  6.   
  7.     BpGraphicBufferProducer(constsp& impl)  
  8.   
  9.         :BpInterface(impl)  
  10.   
  11.     {  
  12.   
  13.     }  
  14.   
  15.     virtual status_t requestBuffer(intbufferIdx, sp* buf) {  
  16.   
  17.         Parcel data, reply;  
  18.   
  19.        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());  
  20.   
  21.         data.writeInt32(bufferIdx);  
  22.   
  23.         status_t result =remote()->transact(REQUEST_BUFFER, data,&reply);  
  24.   
  25.         if (result != NO_ERROR) {  
  26.   
  27.             return result;  
  28.   
  29.         }  
  30.   
  31.         bool nonNull = reply.readInt32();  
  32.   
  33.         if (nonNull) {  
  34.   
  35.             *buf = new GraphicBuffer();  
  36.   
  37.             reply.read(**buf);  
  38.   
  39.         }  
  40.   
  41.         result = reply.readInt32();  
  42.   
  43.         return result;  
  44.   
  45.     }  
  46.   
  47.     virtual status_t dequeueBuffer(int*buf, sp* fence, bool async,  
  48.   
  49.             uint32_t w, uint32_t h, uint32_tformat, uint32_t usage) {  
  50.   
  51.         Parcel data, reply;  
  52.   
  53.        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());  
  54.   
  55.         data.writeInt32(async);  
  56.   
  57.         data.writeInt32(w);  
  58.   
  59.         data.writeInt32(h);  
  60.   
  61.         data.writeInt32(format);  
  62.   
  63.         data.writeInt32(usage);  
  64.   
  65.         status_t result = remote()->transact(DEQUEUE_BUFFER, data,&reply);  
  66.   
  67.         if (result != NO_ERROR) {  
  68.   
  69.             return result;  
  70.   
  71.         }  
  72.   
  73.         *buf = reply.readInt32();  
  74.   
  75.         bool nonNull = reply.readInt32();  
  76.   
  77.        if (nonNull) {  
  78.   
  79.             *fence = new Fence();  
  80.   
  81.             reply.read(**fence);  
  82.   
  83.         }  
  84.   
  85.         result = reply.readInt32();  
  86.   
  87.         return result;  
  88.   
  89.     }  
  90.   
  91.    
  92.   
  93.     virtual status_t queueBuffer(intbuf,  
  94.   
  95.             const QueueBufferInput& input,QueueBufferOutput* output) {  
  96.   
  97.         Parcel data, reply;  
  98.   
  99.        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());  
  100.   
  101.         data.writeInt32(buf);  
  102.   
  103.         data.write(input);  
  104.   
  105.         status_t result = remote()->transactQUEUE_BUFFER, data, &reply);  
  106.   
  107.         if (result != NO_ERROR) {  
  108.   
  109.             return result;  
  110.   
  111.         }  
  112.   
  113.         memcpy(output,reply.readInplace(sizeof(*output)), sizeof(*output));  
  114.   
  115.         result = reply.readInt32();  
  116.   
  117.         return result;  

 

省去了一些成员函数,只贴出关键成员函数,首先这里的dequeueBufferqueueBuffer并非真正对Buffer进行操作,留意红色部分,会发现他只是发出一个“消息”通知接收方要去

Dequeue一个Bufferqueue一个Buffer。相对应的BnGraphicBufferProducer来接收消息。

BnGraphicBufferProducer中的onTransact负责这件事:

  1. status_tBnGraphicBufferProducer::onTransact(  
  2.   
  3.     uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)  
  4.   
  5. {  
  6.   
  7.     switch(code) {  
  8.   
  9.  case DEQUEUE_BUFFER: {  
  10.   
  11.            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);  
  12.   
  13.             bool async      = data.readInt32();  
  14.   
  15.             uint32_t w      = data.readInt32();  
  16.   
  17.             uint32_t h      =data.readInt32();  
  18.   
  19.             uint32_t format = data.readInt32();  
  20.   
  21.             uint32_t usage  = data.readInt32();  
  22.   
  23.             int buf;  
  24.   
  25.             sp fence;  
  26.   
  27.             int result = dequeueBuffer(&buf, &fence, async, w, h,format, usage);  
  28.   
  29.             reply->writeInt32(buf);  
  30.   
  31.             reply->writeInt32(fence !=NULL);  
  32.   
  33.             if (fence != NULL) {  
  34.   
  35.                 reply->write(*fence);  
  36.   
  37.             }  
  38.   
  39.             reply->writeInt32(result);  
  40.   
  41.             return NO_ERROR;  
  42.   
  43.         } break;  
  44.   
  45.         case QUEUE_BUFFER: {  
  46.   
  47.            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);  
  48.   
  49.             int buf = data.readInt32();  
  50.   
  51.             QueueBufferInput input(data);  
  52.   
  53.             QueueBufferOutput* const output =  
  54.   
  55.                     reinterpret_cast(  
  56.   
  57.                            reply->writeInplace(sizeof(QueueBufferOutput)));  
  58.   
  59.             status_t result = queueBuffer(buf, input, output);  
  60.   
  61.             reply->writeInt32(result);  
  62.   
  63.             return NO_ERROR;  
  64.   
  65.         } break;  
  66.   
  67.          
  68.   
  69.         
  70.   
  71.     }  
  72.   
  73.     return BBinder::onTransact(code, data,reply, flags);  
  74.   
  75. }  

 

省略了一些分支,留意红色部分才发现这里调用了dequeueBufferqueueBuffer

它们的实现在BufferQueue中,这里才真正踏足到BufferQueue领域中。到这里客户端和BufferQueue建立联系,接下去的事就是BufferQueue内部处理的事了,BufferQueueSuefaceFlinger之间的关系也如此。

 

四.             SurfaceFlinger处理buffer

  这里先用2张图来介绍下SurfaceFlinger的整个消息处理机制和工作流程:

更具体的代码流程之前有经过分析。

这里继续下去对handleMessageRefresh分析,这是SuefaceFlinger的核心处理函数。

 

  1. voidSurfaceFlinger::handleMessageRefresh() {  
  2.   
  3.     ATRACE_CALL();  
  4.   
  5.     preComposition();  
  6.   
  7.     rebuildLayerStacks();  
  8.   
  9.     setUpHWComposer();  
  10.   
  11.     doDebugFlashRegions();  
  12.   
  13.     doComposition();  
  14.   
  15. postComposition();  
  16.   
  17.    
  18.   
  19. //………省略  
  20.   
  21. }  

 

 preComposition();预先准备“合成物“就是客户端那边传来的UI信息的buffer

 rebuildLayerStacks();在每一个screen上重建可见区域;

setUpHWComposer();初始化一个硬件容器;

doDebugFlashRegions();这个函数一般进去就返回来了;

doComposition();实质的合成过程,并且合成完的BUFFERopengl es处理,处理之后由postFramebuffer()送到display上显示;

 

这里重点研究doComposition()

 

  1. voidSurfaceFlinger::doComposition() {  
  2.   
  3.     ATRACE_CALL();  
  4.   
  5.     const bool repaintEverything =android_atomic_and(0, &mRepaintEverything);  
  6.   
  7.     for (size_t dpy=0 ; dpy<>
  8.   
  9.         const sp&hw(mDisplays[dpy]);  
  10.   
  11.         if (hw->canDraw()) {  
  12.   
  13.             // transform the dirty region intothis screen's coordinate space  
  14.   
  15.             const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));  
  16.   
  17.    
  18.   
  19.             // repaint the framebuffer (ifneeded)  
  20.   
  21.             doDisplayComposition(hw, dirtyRegion);  
  22.   
  23.    
  24.   
  25.            hw->dirtyRegion.clear();  
  26.   
  27.             hw->flip(hw->swapRegion);  
  28.   
  29.            hw->swapRegion.clear();  
  30.         }  
  31.   
  32.         // inform the h/w that we're donecompositing  
  33.   
  34.       hw->compositionComplete();  
  35.     }  
  36.   
  37.     postFramebuffer();  
  38. }  

 

doDisplayComposition(hw, dirtyRegion);负责渲染的核心函数它的走向是:

doDisplayComposition-> doComposeSurfaces->draw->onDraw->drawWithOpenGL.一直走到OPENGL层。Opengl贴完图之后,调用了flip函数,在这里跟之前版本有很大出入,之前版本flip是在postFramebuffer中的,而且函数内容也做了很大的改变,只是计数加一。

   在这里说明一下,UI显示是双缓冲机制,每当画完一个buffer需要flip一下,也就是交换。但在这个版本已经融合到postFramebuffer中:

贴出关键代码

r = hwc.commit();

成员变量hwc是在DisplayHardware::init中生成的一个HWComposer对象。只要HWC_HARDWARE_MODULE_ID模块可以正常加载,且hwc_open能打开hwc_composer_device设备,那么initCheck()就返回NO_ERROR,否则就是NO_INIT

此时我们通过HWComposer::commit来执行flip,这个函数直接调用如下硬件接口:

mHwc->set(mHwc, mNumDisplays, mLists);

set()和后面的eglSwapBuffers是基本等价的,原型如下:

   int (*set)(struct hwc_composer_device*dev,hwc_display_t dpy,

               hwc_layer_list_t* list);

其中最后一个list必须与最近一次的prepare()所用列表完全一致。假如list为空或者列表数量为0的话,说明SurfaceFlinger已经利用OpenGL ES做了composition,此时set就和eglSwapBuffers一样。当list不为空,且layercompositionType == HWC_OVERLAY,那么HWComposer需要进行硬件合成。

如果成功执行的话,set返回0,否则就是HWC_EGL_ERROR

如果没成功的话,后面还有一句:

if (r)

 {

 hw->hwcSwapBuffers();

}

作用也是跟flip一样。它的函数走向是:

hwcSwapBuffers->eglSwapBuffers->swapBuffers->advanceFrame-> fbPost->post

一旦交换完毕就顺着这个走向抛给底层display去显示。

这里我们主要研究swapBuffers这个函数:

 

  1. EGLBooleanegl_window_surface_v2_t::swapBuffers()  
  2.   
  3. {  
  4.   
  5.     //………….  
  6.   
  7.     nativeWindow->queueBuffer(nativeWindow,buffer, -1);  
  8.   
  9.    
  10.   
  11.     // dequeue a new buffer  
  12.   
  13.     if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd)== NO_ERROR) {  
  14.   
  15.         sp fence(new Fence(fenceFd));  
  16.   
  17.         if(fence->wait(Fence::TIMEOUT_NEVER)) {  
  18.   
  19.            nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);  
  20.   
  21.             return setError(EGL_BAD_ALLOC,EGL_FALSE);  
  22.   
  23.         }  
  24.   
  25. //。。。。。。  
  26.   
  27. }  


 

这和我一开始的那张图的流程是一致的——通过queueBuffer来入队,然后通过dequeueBuffer重新申请一个buffer以用于下一轮的刷新

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多