Android4.4深入浅出之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:
- wp<ConsumerListener>mConsumerListener;
- }
这样子就很清楚了,当有一帧数据准备就绪后,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>& 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之间的关系也如此。
四. 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<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以用于下一轮的刷新。
Android4.4深入浅出之SurfaceFlinger总体结构相关推荐
- Android4.4深入浅出之SurfaceFlinger与Client通信框架(一)
SurfaceFlinger框架是基于Binder进程间通信机制搭建的,SF作为一个服务进程,用户程序想要跟它通信必然要经过Binder机制.首先说一下,用户要跟SF通信,那么SF必须出现在Servi ...
- jquery源码学习笔记一:总体结构
练武不练功,到老一场空.计算机也一样. 计算机的功,就是原理.如果程序员只会使用各种函数,各种框架,而不知其原理,顶多熟练工人而已.知其然,更要知其所以然. jquery我们用得很爽,但它究竟咋实现的 ...
- wireshark 总体结构
1. 总体结构 wireshark的总体结构如下图所示. 2. 功能模块 模块名 功能 源码子目录 GTK/Qt 处理所有的用户输入/输出(所有的窗口,对话框等等) /ui GTK: /ui/gtk ...
- 【转】Tomcat总体结构(Tomcat源代码阅读系列之二)
本文是Tomcat源代码阅读系列的第二篇文章,我们在本系列的第一篇文章:在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码一文中介绍了如何在intelliJ IDEA 和 Ec ...
- 磁悬浮惯性动量轮技术_第2章_磁悬浮惯性动量轮的总体结构
文章目录 2.1 引言 2.2 磁悬浮惯性动量轮整体结构 2.2.1 磁悬浮惯性动量轮转子结构 2.2.2 磁悬浮惯性动量轮定子结构 2.3 磁悬浮惯性动量轮磁轴承结构及构型 2.3.1 磁轴承工作原 ...
- 海量传感数据管理系统功能要求与总体结构
海量传感数据管理系统的设计 1 海量传感数据管理系统的设计要求 需要满足以下功能要求: 传感数据上传功能 要求无线传感器可以自动采集传感数据自行上传,可以通过汇聚节点连接的计算机由Internet上传 ...
- 51单片机电子钟 是如何做成的(3)---电子钟总体结构与操作
五一劳动节过了,我又回来了,上次说到哪来了?说到我把例程都抄完了,流程图也清晰度画了出来,那么,对单片机的程序的总体结构和需要的器件都有个大致的了解,所以,这一博客(本期),将会有如下内容: 需要的功 ...
- Vue后台管理页面总体结构及主要功能设计
后台管理页面总体结构为:顶部左侧为系统标题,顶部右侧为用户图标及改密.退出菜单.中间左侧为功能菜单,中间右侧为操作区域,可以用el-row配合el-col来实现布局.其中导航菜单可以用el-menu配 ...
- 论文的总体结构及质量控制
要写出一篇高质量AI领域的论文,首先要搞清楚论文由哪几部分组成,即论文的总体结构.同时,还要了解AI论文的质量评价与质量控制的指标.这样做的目的是为了弄明白AI论文的结构以及什么样的AI论文才是好的论 ...
最新文章
- CUDA 7 Stream流简化并发性
- android 收不到短信广播,android – 短信广播接收器没有得到textmessage
- 使用common-fileUpload制作文件上传【转】
- 信息学奥赛一本通 2035:【例5.2】平移数据
- 马云欣赏你,你的创业就已成功了一半
- innobackupex做MySQL增量备份及恢复
- 独家揭秘!抖音爆款实时视频漫画变身特效背后技术
- Redis数据结构04-SortedSet
- 解析mysqlbinlog日志_关于mysql-binlog日志解析框架
- Flutter进阶第13篇: 打开外部浏览器、打开外部应用、拨打电话、发送短信
- IOS 拉伸图片(封装)
- 数据库 SQL Server2012安装步骤详解
- LTspice基础教程-004.系统自带仿真库介绍
- AI 人工智能包含的领域方向
- 后台站点-菜单管理功能(一)
- JVM--查看堆栈信息
- 产品经理培训有必要吗?
- 数学建模之多元非线性回归
- JS调用新旧windowsMedia的方法
- 《趣学Python编程》——第1部分 学习编程 第1章 Python不是大蟒蛇 1.1 关于计算机语言...
热门文章
- PAT (Advanced Level) 1051. Pop Sequence (25)
- 简单的BBcode parsing
- 转 Linux查看文件编码格式及文件编码转换
- 使用QT + cocos2dx制作工具
- 论大学毕业后是否适合创业
- 保护系统 用SVS为Windows穿上“层层”防弹衣
- cmake使用教程(四)调用外部共享库和头文件
- python搭建web服务器_用Python建立最简单的web服务器
- Java注解的作用?
- c语言char aa 1000,char ** 与char * a[ ] 区别