Android4.4 GUI系统框架之SurfaceFlinger
SurfaceFlinger:每当用户程序刷新UI的时候,会中介BufferQueue申请一个buffer(dequeueBuffer),然后把UI的信息填入,丢给SurfaceFlinger,SurfaceFlinger通过计算多重计算合成visibleRegion之后,丢给openGL层处理,处理之后送到显示器display上显示。
根据整个Android系统的GUI设计理念,我们不难猜想到至少需要两种本地窗口:
Ø 面向管理者(SurfaceFlinger)
既然SurfaceFlinger扮演了系统中所有UI界面的管理者,那么它无可厚非地需要直接或间接地持有“本地窗口”,这个窗口就是FramebufferNativeWindow
Ø 面向应用程序
这类窗口是Surface(这里和以前版本出入比较大,之前的版本本地窗口是SurfaceTextureClient)
第二种窗口是能直接显示在终端屏幕上的——它使用了帧缓冲区,而第一种Window实际上是从内存缓冲区分配的空间。当系统中存在多个应用程序时,这能保证它们都可以获得一个“本地窗口”,并且这些窗口最终也能显示到屏幕上——SurfaceFlinger会收集所有程序的显示需求,对它们做统一的图像混合操作。
一个UI完全显示到diplay的过程,SurfaceFlinger扮演着重要的角色但是它的职责是“Flinger”,即把系统中所有应用程序的最终的“绘图结果”进行“混合”,然后统一显示到物理屏幕上,而其他方面比如各个程序的绘画过程,就由其他东西来担任了。这个光荣的任务自然而然地落在了BufferQueue的肩膀上,它是每个应用程序“一对一”的辅导老师,指导着UI程序的“画板申请”、“作画流程”等一系列细节。下面的图描述了这三者的关系:
虽说是三者的关系,但是他们所属的层却只有两个,app属于java层,BufferQueue/SurfaceFlinger属于native层。也就是说BufferQueue也是隶属SurfaceFlinger,所有工作围绕SurfaceFlinger展开。
这里IGraphicBufferProducer就是app和BufferQueue重要桥梁,GraphicBufferProducer承担着单个应用进程中的UI显示需求,与BufferQueue打交道的就是它。它的工作流程如下:
BpGraphicBufferProducer是GraphicBufferProducer在客户端这边的代理对象,负责和SF交互,GraphicBufferProducer通过gbp(IGraphicBufferProducer类对象)向BufferQueue获取buffer,然后进行填充UI信息,当填充完毕会通知SF,SF知道后就对该Buffer进行下一步操作。典型的生产-消费者模式。
接下来具体说明客户端(producer)和服务端SurfaceFlinger(consumer)工作的模式:
首先这里的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已经写入完成后,它进一步调用BufferQueue的queue。从字面上看这个函数是“入列”的意思,形象地表达了buffer此时的操作——把buffer归还到BufferQueue的队列中。一旦queue成功后,owner也就随之改变为BufferQueue了
Ø Consumer
消费者是与生产者相对应的,它的操作同样受到BufferQueue的管控。当一块buffer已经就绪后,Consumer就可以开始工作了。这里需要特别留意的是,从各个对象所扮演的角色来看,BufferQueue是中介机构,属于服务提供方;Producer属于buffer内容的产出方,它对缓冲区的操作是一个“主动”的过程;反之,Consumer对buffer的处理则是“被动”的、“等待式”的——它必须要等到一块buffer填充完成后才能做工作。在这样的模型下,我们怎么保证Consumer可以及时的处理buffer呢?换句话说,当一块buffer数据ready后,应该怎么告知Consumer来操作呢?
仔细观察的话,可以看到BufferQueue里还同时提供了一个特别的类,名称为ProxyConsumerListener,其中的函数接口包括:
classProxyConsumerListener : public BnConsumerListener { public: //省略构造函数 virtual void onFrameAvailable();/*当一块buffer可以被消费时,这个函数会被调用,特别注意此时没有共享锁的保护*/ virtual voidonBuffersReleased();/*BufferQueue通知consumer它已经释放其slot中的一个或多个 GraphicBuffer引用*/ private: wp<ConsumerListener>mConsumerListener; }
这样子就很清楚了,当有一帧数据准备就绪后,BufferQueue就会调用onFrameAvailable()来通知Consumer进行消费。
BufferQueue和SurfaceFlinger之间的通信模式如下:
也是有一对BpGraphicBufferConsumer/BnGraphicBufferConsumer支持他们之间的信息传输。
首先说明一下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是IGraphicBufferProducer和IGraphicBufferConsumer的具体实现,用户在请求和SurfaceFlinger连接的过程中会请求SF创建一个Layer,IGraphicBufferProducer就是在这个过程中获取一个BufferQueue对象,又转化成IGraphicBufferProducer类对象,是为了进一步和BufferQueue进行交互,下面是关键代码:
status_t SurfaceFlinger::createNormalLayer(constsp<Client>& client, const String8& name, uint32_t w,uint32_t h, uint32_t flags, PixelFormat& format, sp<IBinder>* handle, sp<IGraphicBufferProducer>*gbpsp<Layer>* outLayer) { switch (format) { case PIXEL_FORMAT_TRANSPARENT: case PIXEL_FORMAT_TRANSLUCENT: format = PIXEL_FORMAT_RGBA_8888; break; case PIXEL_FORMAT_OPAQUE: } #ifdefNO_RGBX_8888 if (format == PIXEL_FORMAT_RGBX_8888) format = PIXEL_FORMAT_RGBA_8888; #endif *outLayer = new Layer(this, client, name,w, h, flags); status_t err =(*outLayer)->setBuffers(w, h, format, flags); if (err == NO_ERROR) { *handle = (*outLayer)->getHandle(); *gbp =(*outLayer)->getBufferQueue(); } ALOGE_IF(err, "createNormalLayer()failed (%s)", strerror(-err)); return err; }
下面是getBufferQueue的实现,很简单,获取BufferQueue对象:
sp<IGraphicBufferProducer>Layer::getBufferQueue() const { return mBufferQueue; }
IGraphicBufferProducer是个接口类,它的实现必然在子类BpGraphicBufferProducer中实现,我们来看下这个类:
classBpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> { public: BpGraphicBufferProducer(constsp<IBinder>& impl) :BpInterface<IGraphicBufferProducer>(impl) { } virtual status_t requestBuffer(intbufferIdx, sp<GraphicBuffer>* buf) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(bufferIdx); status_t result =remote()->transact(REQUEST_BUFFER, data,&reply); if (result != NO_ERROR) { return result; } bool nonNull = reply.readInt32(); if (nonNull) { *buf = new GraphicBuffer(); reply.read(**buf); } result = reply.readInt32(); return result; } virtual status_t dequeueBuffer(int*buf, sp<Fence>* fence, bool async, uint32_t w, uint32_t h, uint32_tformat, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(async); data.writeInt32(w); data.writeInt32(h); data.writeInt32(format); data.writeInt32(usage); status_t result = remote()->transact(DEQUEUE_BUFFER, data,&reply); if (result != NO_ERROR) { return result; } *buf = reply.readInt32(); bool nonNull = reply.readInt32(); if (nonNull) { *fence = new Fence(); reply.read(**fence); } result = reply.readInt32(); return result; } virtual status_t queueBuffer(intbuf, const QueueBufferInput& input,QueueBufferOutput* output) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(buf); data.write(input); status_t result = remote()->transactQUEUE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; } memcpy(output,reply.readInplace(sizeof(*output)), sizeof(*output)); result = reply.readInt32(); return result;
省去了一些成员函数,只贴出关键成员函数,首先这里的dequeueBuffer和queueBuffer并非真正对Buffer进行操作,留意红色部分,会发现他只是发出一个“消息”通知接收方要去
Dequeue一个Buffer或queue一个Buffer。相对应的BnGraphicBufferProducer来接收消息。
BnGraphicBufferProducer中的onTransact负责这件事:
status_tBnGraphicBufferProducer::onTransact( uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags) { switch(code) { case DEQUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); bool async = data.readInt32(); uint32_t w = data.readInt32(); uint32_t h =data.readInt32(); uint32_t format = data.readInt32(); uint32_t usage = data.readInt32(); int buf; sp<Fence> fence; int result = dequeueBuffer(&buf, &fence, async, w, h,format, usage); reply->writeInt32(buf); reply->writeInt32(fence !=NULL); if (fence != NULL) { reply->write(*fence); } reply->writeInt32(result); return NO_ERROR; } break; case QUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int buf = data.readInt32(); QueueBufferInput input(data); QueueBufferOutput* const output = reinterpret_cast<QueueBufferOutput*>( reply->writeInplace(sizeof(QueueBufferOutput))); status_t result = queueBuffer(buf, input, output); reply->writeInt32(result); return NO_ERROR; } break; } return BBinder::onTransact(code, data,reply, flags); }
省略了一些分支,留意红色部分才发现这里调用了dequeueBuffer和queueBuffer,
它们的实现在BufferQueue中,这里才真正踏足到BufferQueue领域中。到这里客户端和BufferQueue建立联系,接下去的事就是BufferQueue内部处理的事了,BufferQueue和SuefaceFlinger之间的关系也如此。
这里先用2张图来介绍下SurfaceFlinger的整个消息处理机制和工作流程:
更具体的代码流程之前有经过分析。
这里继续下去对handleMessageRefresh分析,这是SuefaceFlinger的核心处理函数。
voidSurfaceFlinger::handleMessageRefresh() { ATRACE_CALL(); preComposition(); rebuildLayerStacks(); setUpHWComposer(); doDebugFlashRegions(); doComposition(); postComposition(); //………省略 }
preComposition();预先准备“合成物“就是客户端那边传来的UI信息的buffer;
rebuildLayerStacks();在每一个screen上重建可见区域;
setUpHWComposer();初始化一个硬件容器;
doDebugFlashRegions();这个函数一般进去就返回来了;
doComposition();实质的合成过程,并且合成完的BUFFER由opengl es处理,处理之后由postFramebuffer()送到display上显示;
这里重点研究doComposition()
voidSurfaceFlinger::doComposition() { ATRACE_CALL(); const bool repaintEverything =android_atomic_and(0, &mRepaintEverything); for (size_t dpy=0 ; dpy<mDisplays.size(); dpy++) { const sp<DisplayDevice>&hw(mDisplays[dpy]); if (hw->canDraw()) { // transform the dirty region intothis screen's coordinate space const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); // repaint the framebuffer (ifneeded) doDisplayComposition(hw, dirtyRegion); hw->dirtyRegion.clear(); hw->flip(hw->swapRegion); hw->swapRegion.clear(); } // inform the h/w that we're donecompositing hw->compositionComplete(); } postFramebuffer(); }
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不为空,且layer的compositionType == HWC_OVERLAY,那么HWComposer需要进行硬件合成。
如果成功执行的话,set返回0,否则就是HWC_EGL_ERROR。
如果没成功的话,后面还有一句:
if (r)
{
hw->hwcSwapBuffers();
}
作用也是跟flip一样。它的函数走向是:
hwcSwapBuffers->eglSwapBuffers->swapBuffers->advanceFrame-> fbPost->post。
一旦交换完毕就顺着这个走向抛给底层display去显示。
这里我们主要研究swapBuffers这个函数:
EGLBooleanegl_window_surface_v2_t::swapBuffers() { //…………. nativeWindow->queueBuffer(nativeWindow,buffer, -1); // dequeue a new buffer if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd)== NO_ERROR) { sp<Fence> fence(new Fence(fenceFd)); if(fence->wait(Fence::TIMEOUT_NEVER)) { nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd); return setError(EGL_BAD_ALLOC,EGL_FALSE); } //。。。。。。 }
这和我一开始的那张图的流程是一致的——通过queueBuffer来入队,然后通过dequeueBuffer重新申请一个buffer以用于下一轮的刷新。