Android4.4 GUI系统框架之SurfaceFlinger 一. Android GUI框架:SurfaceFlinger:每当用户程序刷新UI的时候,会中介BufferQueue申请一个buffer(dequeueBuffer),然后把UI的信息填入,丢给SurfaceFlinger,SurfaceFlinger通过计算多重计算合成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就是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:
-
- wpmConsumerListener;
-
- }
这样子就很清楚了,当有一帧数据准备就绪后,BufferQueue就会调用onFrameAvailable()来通知Consumer进行消费。 BufferQueue和SurfaceFlinger之间的通信模式如下: 也是有一对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是IGraphicBufferProducer和IGraphicBufferConsumer的具体实现,用户在请求和SurfaceFlinger连接的过程中会请求SF创建一个Layer,IGraphicBufferProducer就是在这个过程中获取一个BufferQueue对象,又转化成IGraphicBufferProducer类对象,是为了进一步和BufferQueue进行交互,下面是关键代码: - status_t SurfaceFlinger::createNormalLayer(constsp& client,
-
- const String8& name, uint32_t w,uint32_t h, uint32_t flags, PixelFormat& format,
-
- sp* handle, sp*gbpsp* 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对象: - spLayer::getBufferQueue() const {
-
- return mBufferQueue;
-
- }
IGraphicBufferProducer是个接口类,它的实现必然在子类BpGraphicBufferProducer中实现,我们来看下这个类: - classBpGraphicBufferProducer : public BpInterface
-
- {
-
- public:
-
- BpGraphicBufferProducer(constsp& impl)
-
- :BpInterface(impl)
-
- {
-
- }
-
- virtual status_t requestBuffer(intbufferIdx, sp* 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, 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;
-
- 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(
-
- 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之间的关系也如此。 四. SurfaceFlinger处理buffer 这里先用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<>
-
- const sp&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(new Fence(fenceFd));
-
- if(fence->wait(Fence::TIMEOUT_NEVER)) {
-
- nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
-
- return setError(EGL_BAD_ALLOC,EGL_FALSE);
-
- }
-
- //。。。。。。
-
- }
这和我一开始的那张图的流程是一致的——通过queueBuffer来入队,然后通过dequeueBuffer重新申请一个buffer以用于下一轮的刷新
|