您的位置:首页 > 产品设计 > UI/UE

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

2013-05-21 14:12 489 查看
文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。
转载请注明: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,大家注意辨别。我们将重点的部分通过高显帮大家划出来,即下面几个函数:
l  handleTransaction
即处理事务,什么样的事务呢?在SurfaceFlinger::setTransactionState()中我们可以看到,假如当前的orientation和新的不符合时,会将eTransactionNeeded置位;当应用程序请求createSurface、removeSurface,或者addLayer、removeLayer时也会把它置位。另一个flag被置位的情况则包括:layer的size、alpha、matrix、transparentregion、visibility变化等等。
总结起来,就是当与系统显示相关的状态(比如新增/减少了Surface,显示屏的变化等等)改变,或者某个Layer自身状态(比如它的大小尺寸、可见性、透明度等等)改变时,就需要执行Transaction。
 
l  handlePageFlip
由前面的分析我们知道,每个Layer对应着最多32个BufferSlot,这样系统在进行一次刷新时,必须先决定使用哪个buffer,并利用这一缓冲区更新纹理。另外,我们还需要计算所有图层的可见区域和“脏区域”,以便最终的合成显示。
 
l  handleRefresh
版本更新遗留下的函数,当前实现中没有起到作用,相信在后续升级中会进一步完善。
 
l  handleWorkList
创建HWComposer中的mList,这个列表将用于后续的layer合成。这个函数比较简单,我们不单独介绍。
 
l  handleRepaint
计算出最终的脏区域,并执行实际的合成工作(composeSurfaces),我们将做详细源码分析。
 
l  postFramebuffer
将上一步中生成的缓冲区数据post到framebuffer中,这样才能真正在物理屏幕上显示出来。分为两条路径,即HWComposer::commit和直接调用eglSwapBuffers()
 
这些函数基本涵盖了SurfaceFlinger的所有功能,接下来的几个小节我们将详细分析它们,各个击破。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: