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:
wpmConsumerListener;
}
这样子就很清楚了,当有一帧数据准备就绪后,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,
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之间的关系也如此。
这里先用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&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以用于下一轮的刷新。