现在的位置: 首页 > 综合 > 正文

GUI系统之SurfaceFlinger(13)VSync信号的处理

2014年09月05日 ⁄ 综合 ⁄ 共 3648字 ⁄ 字号 评论关闭

文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。
转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/

GUI系统之SurfaceFlinger章节目录:
blog.csdn.net/uiop78uiop78/article/details/8954508

1.1.1 VSync信号的处理

经过上一小节的分析,现在我们已经明白了系统是如何通过硬件设备或者软件模拟来产生VSync信号的,也明白了它的流转过程。VSync最终会被EventThread::threadLoop()分发给各监听者,在当前版本中是MessageQueue。

MessageQueue通过与EventThread建立一个Connection来监听事件,简图如下:

图 11‑35 Connection代表了EventThread和对事件感兴趣的对象的连接

 

对VSYNC等事件感兴趣的对象,比如MessageQueue,首先要通过EventThread::createEventConnection()来建立一个连接,实际上就是生成了一个EventThread::Connection对象。这个对象将对双方产生如下影响:

l  当Connection::onFirstRef()时,它会主动调用EventThread::registerDisplayEventConnection()来把自己加入到mDisplayEventConnections中,这是保证事件发生后EventThread能找到“连接”的关键一步

l  当MessageQueue得到Connection后,它会马上调用getDataChannel来获得一个BitTube。从逻辑关系上看,Connection只是双方业务上连接,而BitTube则是数据传输通道,各种Event信息就是通过这里传输的

 

void MessageQueue::setEventThread(const sp<EventThread>&eventThread)

{

    mEventThread =eventThread;

    mEvents = eventThread->createEventConnection(); //建立一个Connection

    mEventTube = mEvents->getDataChannel();//马上获取BitTube

    mLooper->addFd(mEventTube->getFd(), 0,ALOOPER_EVENT_INPUT, MessageQueue::cb_eventReceiver, this);

}

从扮演的角色上来看,EventThread是Server,不断地往Tube中写入数据;而MessageQueue是Client,负责读取数据。可能有人会很好奇,MessageQueue如何得知有Event到来,然后去读取它呢?答案就是它们之间的数据读写模式采用的是Socket(AF_UNIX域)。

上面这个函数的末尾,通过Looper添加了一个fd,这实际上就是Socket pair中的一端。然后Looper将这个fd与其callback函数(即MessageQueue::cb_eventReceiver)加入全局的mRequests进行管理。

KeyedVector<int, Request> mRequests;

这个Vector会集中所有需要监测的fd,这样当Looper进行pollInner时,只要有事件需要处理,它就可以通过回调函数通知“接收者”。这里面的实现细节主要包括BitTube.cpp和Looper.cpp,有兴趣的读者可以自行研究下。

当Event发生后,MessageQueue::cb_eventReceiver开始执行,进而调用eventReceiver。如果event的类型是DisplayEventReceiver::DISPLAY_EVENT_VSYNC,这是我们想要监听的事件,所以再调用mHandler->signalRefresh():

void MessageQueue::Handler::signalRefresh() {

    if((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh)== 0) {

        mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));

    }

}

根据前几个小节我们分析的SurfaceThread工作模式,这个Message会进入它的消息处理队列,然后在SurfaceFlinger::onMessageReceived()中得到处理:

void SurfaceFlinger::onMessageReceived(int32_t what)

{…

    switch (what) {

        caseMessageQueue::REFRESH: {

            const uint32_tmask = eTransactionNeeded | eTraversalNeeded;

            uint32_ttransactionFlags = peekTransactionFlags(mask);

            if(CC_UNLIKELY(transactionFlags)) {

                handleTransaction(transactionFlags);

            }

            handlePageFlip();

            handleRefresh();

            constDisplayHardware& hw(graphicPlane(0).displayHardware());

            …

            if(CC_LIKELY(hw.canDraw())) {

                handleRepaint();

               hw.compositionComplete();

                postFramebuffer();

            } else {

               hw.compositionComplete();

            }

        } break;

    }

}

经过几个版本的变迁,现在SurfaceFlinger只处理REFRESH一个消息,不过源码中遗留下了很多没用的代码J,大家注意辨别。我们将重点的部分通过高显帮大家划出来,即下面几个函数:

handleTransaction

即处理事务,什么样的事务呢?在SurfaceFlinger::setTransactionState()中我们可以看到,假如当前的orientation和新的不符合时,会将eTransactionNeeded置位;当应用程序请求createSurfaceremoveSurface,或者addLayerremoveLayer时也会把它置位。另一个flag被置位的情况则包括:layersizealphamatrixtransparentregionvisibility变化等等。

总结起来,就是当与系统显示相关的状态(比如新增/减少了Surface,显示屏的变化等等)改变,或者某个Layer自身状态(比如它的大小尺寸、可见性、透明度等等)改变时,就需要执行Transaction

 

handlePageFlip

由前面的分析我们知道,每个Layer对应着最多32BufferSlot,这样系统在进行一次刷新时,必须先决定使用哪个buffer,并利用这一缓冲区更新纹理。另外,我们还需要计算所有图层的可见区域和“脏区域”,以便最终的合成显示。

 

handleRefresh

版本更新遗留下的函数,当前实现中没有起到作用,相信在后续升级中会进一步完善。

 

handleWorkList

创建HWComposer中的mList,这个列表将用于后续的layer合成。这个函数比较简单,我们不单独介绍。

 

handleRepaint

计算出最终的脏区域,并执行实际的合成工作(composeSurfaces),我们将做详细源码分析。

 

postFramebuffer

将上一步中生成的缓冲区数据postframebuffer中,这样才能真正在物理屏幕上显示出来。分为两条路径,即HWComposer::commit和直接调用eglSwapBuffers()

 

这些函数基本涵盖了SurfaceFlinger的所有功能,接下来的几个小节我们将详细分析它们,各个击破。

抱歉!评论已关闭.