Android 4.4 Graphic系统详解(2) VSYNC的生成

VSYNC 的概念

VSYNC(Vertical Synchronization)是一个相当古老的概念,对于游戏玩家,它有一个更加大名鼎鼎的中文名字—-垂直同步。
“垂直同步(vsync)”指的是显卡的输出帧数和屏幕的垂直刷新率相同,这完全是一个CRT显示器上的概念。其实无论是VSYNC还是垂直同步这个名字,因为LCD根本就没有垂直扫描的这种东西,因此这个名字本身已经没有意义。但是基于历史的原因,这个名称在图形图像领域被沿袭下来。
在当下,垂直同步的含义我们可以理解为,使得显卡生成帧的速度和屏幕刷新的速度的保持一致。举例来说,如果屏幕的刷新率为60Hz,那么生成帧的速度就应该被固定在1/60 s。

Android中的VSYNC — 黄油计划

从Android 4.1开始,谷歌致力于解决Android系统中最饱受诟病的一个问题,滑动不如iOS流畅。因谷歌在4.1版本引入了一个重大的改进—Project Butter,也即是黄油计划。
Project Butter对Android Display系统进行了重构,引入了三个核心元素,即VSYNC、Triple Buffer和Choreographer。关于后面两个概念我们会在后面开专题讲解,这里我们重点讲解VSYNC的作用。
玩过大型PC游戏的玩家都知道,VSYNC最重要的作用是防止出现画面撕裂(screentearing)。所谓画面撕裂,就是指一个画面上出现了两帧画面的内容,如下图。
此处输入图片的描述

为什么会出现这种情况呢?这种情况一般是因为显卡输出帧的速度高于显示器的刷新速度,导致显示器并不能及时处理输出的帧,而最终出现了多个帧的画面都留在了显示器上的问题。这也就是我们所说的画面撕裂。

提到垂直同步这里就多提一句,其实我认为对于PC上的大型游戏来说,只有配置足够高,高到显卡输出帧率可以稳定的高于显示器的刷新频率,才有开启垂直同步的必要。因为只有这个时候,画面撕裂才会真正成为一个问题。而对于很多情况下主机性能不足导致游戏输出帧率低于显示器的刷新频率的情况下,尤其是帧率稳定在40~60之间时,开启垂直同步可能会导致帧率倍数级的下降(具体原因我们在Graphic架构一文中提到过,当帧生成速度不及VSync速度时,帧率的下降不是平缓的,而且很可能是倍数级的。当然这在android系统上并非严重问题,因为android上很少有高速的复杂场景的频繁切换。事实上,在Android的普通应用场景下,VSync的使用不仅不会降低帧率,还可以有效解决卡顿问题)。

回到正文中来,那么VSync除了可以解决画面的撕裂的问题,还可以解决别的什么问题吗?我们来看下图:
此处输入图片的描述

这个图中有三个元素,Display是显示屏幕,GPU和CPU负责渲染帧数据,每个帧以方框表示,并以数字进行编号,如0、1、2等等。VSync用于指导双缓冲区的交换。
以时间的顺序来看下将会发生的异常:
Step1. Display显示第0帧数据,此时CPU和GPU渲染第1帧画面,而且赶在Display显示下一帧前完成
Step2. 因为渲染及时,Display在第0帧显示完成后,也就是第1个VSync后,正常显示第1帧
Step3. 由于某些原因,比如CPU资源被占用,系统没有及时地开始处理第2帧,直到第2个VSync快来前才开始处理
Step4. 第2个VSync来时,由于第2帧数据还没有准备就绪,显示的还是第1帧。这种情况被Android开发组命名为“Jank”。
Step5. 当第2帧数据准备完成后,它并不会马上被显示,而是要等待下一个VSync。
所以总的来说,就是屏幕平白无故地多显示了一次第1帧。原因大家应该都看到了,就是CPU没有及时地开始着手处理第2帧的渲染工作,以致“延误军机”。

其实总结上面的这个情况之所以发生,首先的原因就在于第二帧没有及时的绘制(当然即使第二帧及时绘制,也依然可能出现Jank,这就是同时引入三重缓冲的作用。我们将在三重缓冲一节中再讲解这种情况)。那么如何使得第二帧即使被绘制呢?
这就是我们在Graphic系统中引入VSYNC的原因,考虑下面这张图:

此处输入图片的描述

如上图所示,一旦VSync出现后,立刻就开始执行下一帧的绘制工作。这样就可以大大降低Jank出现的概率。另外,VSYNC引入后,要求绘制也只能在收到VSYNC消息之后才能进行,因此,也就杜绝了另外一种极端情况的出现—-CPU(GPU)一直不停的进行绘制,帧的生成速度高于屏幕的刷新速度,导致生成的帧不能被显示,只能丢弃,这样就出现了丢帧的情况—-引入VSYNC后,绘制的速度就和屏幕刷新的速度保持一致了。

VSYNC信号的生成

那么VSYNC信号是如何生成的呢?
Android系统中VSYNC信号分为两种,一种是硬件生成的信号,一种是软件模拟的信号。
硬件信号是由HardwareComposer提供的,HWC封装了相关的HAL层,如果硬件厂商提供的HAL层实现能定时产生VSYNC中断,则直接使用硬件的VSYNC中断,否则HardwareComposer内部会通过VSyncThread来模拟产生VSYNC中断(其实现很简单,就是sleep固定时间,然后唤醒)。

回到我们上一节中讲到的SurfaceFlinger的启动过程inti函数上来,上一节我们提到init函数内会创建一个HWComposer对象。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. HWComposer::HWComposer(  
  2.         const sp<SurfaceFlinger>& flinger,  
  3.         EventHandler& handler)  
  4.     : mFlinger(flinger),  
  5.       mFbDev(0), mHwc(0), mNumDisplays(1),  
  6.       mCBContext(new cb_context),  
  7.       mEventHandler(handler),  
  8.       mDebugForceFakeVSync(false)  
  9. {  
  10. ...  
  11.     //首先是一些和VSYNC有关的信息的初始化  
  12.     //因为在硬件支持的情况下,VSYNC的功能就是由HWC提供的  
  13.     for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {  
  14.         mLastHwVSync[i] = 0;  
  15.         mVSyncCounts[i] = 0;  
  16.     }  
  17.     //根据配置来看是否需要模拟VSYNC消息  
  18.     char value[PROPERTY_VALUE_MAX];  
  19.     property_get("debug.sf.no_hw_vsync", value, "0");  
  20.     mDebugForceFakeVSync = atoi(value);  
  21.     ...  
  22.     // don't need a vsync thread if we have a hardware composer  
  23.     needVSyncThread = false;  
  24.     // always turn vsync off when we start,只是暂时关闭信号,后面会再开启  
  25.     eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);      
  26.   
  27.     //显然,如果需要模拟VSync信号的话,我们需要线程来做这个工作  
  28.     if (needVSyncThread) {  
  29.         // we don't have VSYNC support, we need to fake it  
  30.         //VSyncThread类的实现很简单,无非就是一个计时器而已,定时发送消息而已  
  31.         //TODO VSYNC专题  
  32.         mVSyncThread = new VSyncThread(*this);  
  33.     }  
  34. ...  
  35. }  
  36.   
  37. HWComposer::HWComposer(  
  38.         const sp<SurfaceFlinger>& flinger,  
  39.         EventHandler& handler)  
  40.     : mFlinger(flinger),  
  41.       mFbDev(0), mHwc(0), mNumDisplays(1),  
  42.       mCBContext(new cb_context),  
  43.       mEventHandler(handler),  
  44.       mDebugForceFakeVSync(false)  
  45. {  
  46. ...  
  47.     //首先是一些和VSYNC有关的信息的初始化  
  48.     //因为在硬件支持的情况下,VSYNC的功能就是由HWC提供的  
  49.     for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {  
  50.         mLastHwVSync[i] = 0;  
  51.         mVSyncCounts[i] = 0;  
  52.     }  
  53.     //根据配置来看是否需要模拟VSYNC消息  
  54.     char value[PROPERTY_VALUE_MAX];  
  55.     property_get("debug.sf.no_hw_vsync", value, "0");  
  56.     mDebugForceFakeVSync = atoi(value);  
  57.     ...  
  58.     // don't need a vsync thread if we have a hardware composer  
  59.     needVSyncThread = false;  
  60.     // always turn vsync off when we start,只是暂时关闭信号,后面会再开启  
  61.     eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);      
  62.   
  63.     //显然,如果需要模拟VSync信号的话,我们需要线程来做这个工作  
  64.     if (needVSyncThread) {  
  65.         // we don't have VSYNC support, we need to fake it  
  66.         //VSyncThread类的实现很简单,无非就是一个计时器而已,定时发送消息而已  
  67.         //TODO VSYNC专题  
  68.         mVSyncThread = new VSyncThread(*this);  
  69.     }  
  70. ...  
  71. }  

我们来看下上面这段代码。
首先mDebugForceFakeVSync是为了调制,可以通过这个变量设置强制使用软件VSYNC模拟。
然后针对不同的屏幕,初始化了他们的mLastHwVSync和mVSyncCounts值。
如果硬件支持,那么就把needVSyncThread设置为false,表示不需要软件模拟。
接着通过eventControl来暂时的关闭了VSYNC信号,这一点将在下面讲解eventControl时一并讲解。
最后,如果需要软件模拟Vsync信号的话,那么我们将通过一个单独的VSyncThread线程来做这个工作(fake VSYNC是这个线程唯一的作用)。我们来看下这个线程。

软件模拟

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool HWComposer::VSyncThread::threadLoop() {  
  2.     const nsecs_t period = mRefreshPeriod;  
  3.     //当前的时间  
  4.     const nsecs_t now = systemTime(CLOCK_MONOTONIC);  
  5.     //下一次VSYNC到来的时间  
  6.     nsecs_t next_vsync = mNextFakeVSync;  
  7.     //为了等待下个时间到来应该休眠的时间  
  8.     nsecs_t sleep = next_vsync - now;  
  9.     //错过了VSYNC的时间  
  10.     if (sleep < 0) {  
  11.         // we missed, find where the next vsync should be  
  12.         //重新计算下应该休息的时间  
  13.         sleep = (period - ((now - next_vsync) % period));  
  14.         //更新下次VSYNC的时间  
  15.         next_vsync = now + sleep;  
  16.     }  
  17.     //更新下下次VSYNC的时间  
  18.     mNextFakeVSync = next_vsync + period;  
  19.   
  20.     struct timespec spec;  
  21.     spec.tv_sec  = next_vsync / 1000000000;  
  22.     spec.tv_nsec = next_vsync % 1000000000;  
  23.   
  24.     int err;  
  25.     do {  
  26.         //纳秒精度级的休眠  
  27.         err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);  
  28.     } while (err<0 && errno == EINTR);  
  29.   
  30.     if (err == 0) {  
  31.         //休眠之后,到了该发生VSYNC的时间了  
  32.         mHwc.mEventHandler.onVSyncReceived(0, next_vsync);  
  33.     }  
  34.     return true;  
  35. }  

这个函数其实很简单,无非就是一个简单的时间计算,计算过程我已经写在了程序注释里面。总之到了应该发生VSYNC信号的时候,就调用了mHwc.mEventHandler.onVSyncReceived(0, next_vsync)函数来通知VSYNC的到来。

我们注意到mEventHandler实际上是在HWC创建时被传入的,我们来看下HWC创建时的代码.

 
 
  1. mHwc = new HWComposer(this,  
  2.         *static_cast<HWComposer::EventHandler *>(this));  
  3.   
  4.   
  5. class SurfaceFlinger : public BnSurfaceComposer,  
  6.                    private IBinder::DeathRecipient,  
  7.                    private HWComposer::EventHandler  

可以看到这个mEventHandler实际上就是SurfaceFlinger。也就是说,VSYNC信号到来时,SurfaceFlinger的onVSyncReceived函数处理了这个消息。
这里我们暂时先不展开SurfaceFlinger内的逻辑处理,等我们下面分析完硬件实现后,一并进行分析

硬件实现

上面我们讲了软件如何模拟一个VSYNC信号并通知SurfaceFlinger,那么硬件又是如何实现这一点的呢?
我们再一次回到HWC的创建过程中来:

 
 
  1. if (mHwc) {  
  2.        ALOGE("Lee Using %s version %u.%u", HWC_HARDWARE_COMPOSER,  
  3.              (hwcApiVersion(mHwc) >> 24) & 0xff,  
  4.              (hwcApiVersion(mHwc) >> 16) & 0xff);  
  5.        if (mHwc->registerProcs) {  
  6.            mCBContext->hwc = this;  
  7.            mCBContext->procs.invalidate = &hook_invalidate;  
  8.            mCBContext->procs.vsync = &hook_vsync;  
  9.            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))  
  10.                mCBContext->procs.hotplug = &hook_hotplug;  
  11.            else  
  12.                mCBContext->procs.hotplug = NULL;  
  13.            memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));  
  14.            mHwc->registerProcs(mHwc, &mCBContext->procs);  
  15.        }  

来看下上面这段实现。
当HWC有vsync信号生成时,硬件模块会通过procs.vsync来通知软件部分,因此也就是调用了hook_vsync函数。

 
 
  1. void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,  
  2.         int64_t timestamp) {  
  3.     cb_context* ctx = reinterpret_cast<cb_context*>(  
  4.             const_cast<hwc_procs_t*>(procs));  
  5.     ctx->hwc->vsync(disp, timestamp);  
  6. }  
  7.   
  8. void HWComposer::vsync(int disp, int64_t timestamp) {  
  9.     //只有真实的硬件设备才会产生VSYNC  
  10.     if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {  
  11.         {  
  12.             mLastHwVSync[disp] = timestamp;  
  13.         }  
  14.         mEventHandler.onVSyncReceived(disp, timestamp);  
  15. }  

我们发现最后殊途同归,硬件信号最终也通过onVSyncReceived函数通知到了SurfaceFlinger了。下面我们来分析下SurfaceFlinger的处理过程。

Surfaceflinger对VSYNC消息的处理

在4.4之前,本来SurfaceFlinger对VSYNC的处理比较简单,只是通知EventThread进行处理即可,但是KK再次对VSYNC这一段的逻辑进一步的细化和复杂化。不得不说,Google为了提升Android UI的流畅性真是费尽心思。

虽然只是一个简单的信号,但是KK的处理已经相当复杂。先来直接看下Surfaceflinger的onVSyncReceived函数:

 
 
  1. void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {  
  2.     bool needsHwVsync = false;  
  3.     {  
  4.         if (type == 0 && mPrimaryHWVsyncEnabled) {  
  5.             needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);  
  6.         }  
  7.     }  
  8.     if (needsHwVsync) {  
  9.         enableHardwareVsync();  
  10.     } else {  
  11.         disableHardwareVsync(false);  
  12.     }  
  13. }  

这段代码很短,但是相当让人困惑,困惑至少有以下三点:

  1. mPrimaryHWVsyncEnabled是干嘛的,是被什么时候赋值的?
  2. enableHardwareVsync和disableHardwareVsync又起到了什么作用?
  3. mPrimaryDispSync是什么?addResyncSample有什么作用?

Surfaceflinger的init函数

要回答这三个问题,我们首先还是得回到SurfaceFlinger的init函数中来。

EventThread的创建

上一节中SF的创建过程中我们提到了EventThread的创建。

 
 
  1. {  
  2. ...  
  3.     // start the EventThread  
  4.     sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,  
  5.             vsyncPhaseOffsetNs, true);  
  6.     mEventThread = new EventThread(vsyncSrc);  
  7.     sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,  
  8.             sfVsyncPhaseOffsetNs, true);  
  9.     mSFEventThread = new EventThread(sfVsyncSrc);  
  10.     mEventQueue.setEventThread(mSFEventThread);  
  11.   
  12.     mEventControlThread = new EventControlThread(this);  
  13.     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);  
  14.   
  15.     // set a fake vsync period if there is no HWComposer  
  16.     if (mHwc->initCheck() != NO_ERROR) {  
  17.         mPrimaryDispSync.setPeriod(16666667);  
  18.     }  
  19. ...  
  20. }  

这里看起来更奇怪了。首先这里有两个看起来几乎一样的DispSyncSource,看起来唯一的区别就是一个偏移时间的不同。
而其实,这两个DispSyncSource就是KK引入的重大变化。Android 4.4(KitKat)引入了VSync的虚拟化,即把硬件的VSync信号先同步到一个本地VSync模型中,再从中一分为二,引出两条VSync时间与之有固定偏移的线程。示意图如下:
此处输入图片的描述
而Google这样修改的目的又是什么呢?
回忆一下我们在Graphic架构一文中指出的,在当前三重缓冲区的架构下,即对于一帧内容,先等App UI画完了,SurfaceFlinger再出场对其进行合并渲染后放入framebuffer,最后整到屏幕上。而现有的VSync模型是让大家一起开始干活。
这个架构其实会产生一个问题,因为App和SurfaceFlinger被同时唤醒,导致他们二者总是一起工作,必然导致VSync来临的时刻,这二者之间产生了CPU资源的抢占。因此,谷歌给这两个工作都加上一个小小的延迟,让这两个工作并不是同时被唤醒,这样大家就可以错开使用资源的高峰期,提高工作的效率。
这两个延迟,其实就分别对应上面代码中的vsyncSrc(绘制延迟)和sfVsyncSrc(合成延迟)。

了解了这些背景知识后,我们来继续看代码,DispSyncSource的初始化如此简单,这里不再详述(当然这里的变量mPrimaryDispSync的值来源让人困惑)。
在创建了两个DispSyncSource变量后,我们使用它们来初始化了两个EventThread。下面我们来详细看下EventThread的创建流程:

 
 
  1.   EventThread::EventThread(const sp<VSyncSource>& src)  
  2.     : mVSyncSource(src),  
  3.       mUseSoftwareVSync(false),  
  4.       mVsyncEnabled(false),  
  5.       mDebugVsyncEnabled(false) {  
  6.   
  7.     for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {  
  8.         mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;  
  9.         mVSyncEvent[i].header.id = 0;  
  10.         mVSyncEvent[i].header.timestamp = 0;  
  11.         mVSyncEvent[i].vsync.count =  0;  
  12.     }  
  13. }  
  14.   
  15. void EventThread::onFirstRef() {  
  16.     run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);  
  17. }  

EventThread的构造函数很简单。重点是它的onFirstRef函数启动了一个EventThread线程,于是下面的代码才是重点:

 
 
  1. bool EventThread::threadLoop() {  
  2.     DisplayEventReceiver::Event event;  
  3.     Vector< sp<EventThread::Connection> > signalConnections;  
  4.     signalConnections = waitForEvent(&event);  
  5.   
  6.     // dispatch events to listeners...  
  7.     const size_t count = signalConnections.size();  
  8.     for (size_t i=0 ; i<count ; i++) {  
  9.         const sp<Connection>& conn(signalConnections[i]);  
  10.         // now see if we still need to report this event  
  11.         status_t err = conn->postEvent(event);  
  12.         if (err == -EAGAIN || err == -EWOULDBLOCK) {  
  13.             // The destination doesn't accept events anymore, it's probably  
  14.             // full. For now, we just drop the events on the floor.  
  15.             // FIXME: Note that some events cannot be dropped and would have  
  16.             // to be re-sent later.  
  17.             // Right-now we don't have the ability to do this.  
  18.             ALOGW("EventThread: dropping event (%08x) for connection %p",  
  19.                     event.header.type, conn.get());  
  20.         } else if (err < 0) {  
  21.             // handle any other error on the pipe as fatal. the only  
  22.             // reasonable thing to do is to clean-up this connection.  
  23.             // The most common error we'll get here is -EPIPE.  
  24.             removeDisplayEventConnection(signalConnections[i]);  
  25.         }  
  26.     }  
  27.     return true;  
  28. }  

上面的函数本身并不复杂,其中调用了一个waitForEvent的函数。这个函数相当之长,为了防止代码展开太多,我们这里暂时不再详细分析这个函数。我们目前只需要知道这个函数的最重要的作用是等待Event的到来,并且查找对event感兴趣的监听者,而在没有event到来时,线程处于休眠状态,等待event的唤醒(我们将在下一篇文章VSYNC的接收和处理中展开分析这个函数)。

这样,EventThread线程就运行起来,处在等待被event唤醒的状态下。

MessageQueue和EventThread建立连接

简单说明完EventThread之后,我们再次回到SurfaceFlinger的init过程中来。回到刚才我们本小节开始我们分析的代码中来:

 
 
  1. {  
  2. ...  
  3.     // start the EventThread  
  4.     sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,  
  5.             vsyncPhaseOffsetNs, true);  
  6.     mEventThread = new EventThread(vsyncSrc);  
  7.     sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,  
  8.             sfVsyncPhaseOffsetNs, true);  
  9.     mSFEventThread = new EventThread(sfVsyncSrc);  
  10.     mEventQueue.setEventThread(mSFEventThread);  
  11. ...  
  12. }  

下面这句 mEventQueue.setEventThread(mSFEventThread);其实很重要,这个函数将SurfaceFlinger的MessageQueue真正和我们刚才创建的EventThread建立起了连接,这样SurfaceFlinger才能真正接收到来自HWC的VSYNC信号。
我们来看下这段代码:

 
 
  1. void MessageQueue::setEventThread(const sp<EventThread>& eventThread)  
  2. {  
  3.     mEventThread = eventThread;  
  4.     mEvents = eventThread->createEventConnection();  
  5.     mEventTube = mEvents->getDataChannel();  
  6.     mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,  
  7.             MessageQueue::cb_eventReceiver, this);  
  8. }  

这里代码逻辑其实很简单,就是创建了一个到EventThread的连接,得到了发送VSYNC事件通知的BitTube,然后监控这个BitTube中的套接字,并且指定了收到通知后的回调函数,MessageQueue::cb_eventReceiver。这样一旦VSync信号传来,函数cb_eventReceiver将被调用。

上面这个过程的原理,应该是使用了linux中的socket通信原理,因为和本文主题关系不大,不再展开。而MessageQueue在收到VSync消息后做了什么,我们将在下一篇文章VSync的接收和处理中详细说明。

EventControlThread

回到SurfaceFlinger的init过程中来,在EventThread创建好,MessageQueue和EventThread建立连接之后,SurfaceFlinger又创建了一个EventControlThread。

 
 
  1. {  
  2. ...  
  3.     mEventQueue.setEventThread(mSFEventThread);  
  4.   
  5.     mEventControlThread = new EventControlThread(this);  
  6.     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);  
  7.   
  8.     // set a fake vsync period if there is no HWComposer  
  9.     if (mHwc->initCheck() != NO_ERROR) {  
  10.         mPrimaryDispSync.setPeriod(16666667);  
  11.     }  
  12. ...  
  13. }  

我们来看下这个EventControlThread是做什么的:

 
 
  1. EventControlThread::EventControlThread(const sp<SurfaceFlinger>& flinger):  
  2.         mFlinger(flinger),  
  3.         mVsyncEnabled(false) {  
  4. }  
  5.   
  6. bool EventControlThread::threadLoop() {  
  7.     Mutex::Autolock lock(mMutex);  
  8.     bool vsyncEnabled = mVsyncEnabled;  
  9.     mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC,  
  10.             mVsyncEnabled);  
  11.     while (true) {  
  12.         status_t err = mCond.wait(mMutex);  
  13.         if (err != NO_ERROR) {  
  14.             ALOGE("error waiting for new events: %s (%d)",  
  15.                 strerror(-err), err);  
  16.             return false;  
  17.         }  
  18.         if (vsyncEnabled != mVsyncEnabled) {  
  19.             mFlinger->eventControl(HWC_DISPLAY_PRIMARY,  
  20.                     SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled);  
  21.             vsyncEnabled = mVsyncEnabled;  
  22.         }  
  23.     }  
  24.     return false;  
  25. }  
  26. void SurfaceFlinger::eventControl(int disp, int event, int enabled) {  
  27.     getHwComposer().eventControl(disp, event, enabled);  
  28. }  

其实EventControlThread的功能很简单,从名字里面我们就可以看出来,这个线程最重要的作用就是给HWC硬件发送消息,来通知开启或者关闭VSync消息的。
从代码来看,线程开始时,根据当前状态来通知硬件是否要发送VSync信号(刚开始时应该是关闭的)。然后进入等待:mCond.wait(mMutex),等待的信号来源也很简单:

 
 
  1. void EventControlThread::setVsyncEnabled(bool enabled) {  
  2.     Mutex::Autolock lock(mMutex);  
  3.     mVsyncEnabled = enabled;  
  4.     mCond.signal();  
  5. }  

也就是说,一旦有人调用了EventControlThread的setVsyncEnabled函数时,将发送通知,然后条件被触发,EventControlThread根据当前最新的状态来重新给硬件发送命令,来告知硬件是否要开启VSync信号。那么是谁在什么时候调用了setVsyncEnabled函数呢?我们这里先不跟进,等到下一小节我们讲完屏幕的点亮和熄灭后大家就会明白这一段。

onScreenAcquired

Surfaceflinger的init函数中,除了和EventThread相关的代码外,还有一段显示设备的初始化:

 
 
  1. {  
  2. ...  
  3.     // set initial conditions (e.g. unblank default device)  
  4.     initializeDisplays();  
  5. ...  
  6. }  

我们在上一篇文档SF的创建过程中已经讲解过,其中initializeDisplays函数调用了一个重要的函数onScreenAcquired,前面文档中我们也说过,这个函数不仅在这里会被调用,同样会在屏幕点亮时被调用。

 
 
  1. void SurfaceFlinger::onScreenAcquired(const sp<const DisplayDevice>& hw) {  
  2.     ...  
  3.     if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {  
  4.         // built-in display, tell the HWC  
  5.         getHwComposer().acquire(type);  
  6.         if (type == DisplayDevice::DISPLAY_PRIMARY) {  
  7.             // FIXME: eventthread only knows about the main display right now  
  8.             mEventThread->onScreenAcquired();  
  9.             resyncToHardwareVsync(true);  
  10.         }  
  11.     }  
  12.     ...  
  13. }  

首先我们来看下EventThread类的onScreenAcquired函数:

 
 
  1. void EventThread::onScreenAcquired() {  
  2.     Mutex::Autolock _l(mLock);  
  3.     if (mUseSoftwareVSync) {  
  4.         // resume use of h/w vsync  
  5.         mUseSoftwareVSync = false;  
  6.         mCondition.broadcast();  
  7.     }  
  8. }  

记得我们前面在讲EventThread时提到的,EventThread开始threadLoop以后,会在waitForEvent中等待被通知,而这个被等待的通知。就是在这个onScreenAcquired函数中发出的通知,mCondition.broadcast()(当VSYNC信号到达时,也会发出这个通知)。

继续看下resyncToHardwareVsync函数:

 
 
  1. void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {  
  2.     if (makeAvailable) {  
  3.         mHWVsyncAvailable = true;  
  4.     } else if (!mHWVsyncAvailable) {  
  5.         ALOGE("resyncToHardwareVsync called when HW vsync unavailable");  
  6.         return;  
  7.     }  
  8.     const nsecs_t period =  
  9.             getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);  
  10.   
  11.     mPrimaryDispSync.reset();  
  12.     mPrimaryDispSync.setPeriod(period);  
  13.   
  14.     if (!mPrimaryHWVsyncEnabled) {  
  15.         mPrimaryDispSync.beginResync();  
  16.         mEventControlThread->setVsyncEnabled(true);  
  17.         mPrimaryHWVsyncEnabled = true;  
  18.     }  
  19. }  

这个函数是一个比较重要的函数。主要的功能就是打开HWC的VSync功能。
首先是获取HWC的信号发送间隔,设置给mPrimaryDispSync,然后重置mPrimaryDispSync。
如果之前没有使用HWC的VSYNC,那么还需要重新开始mPrimaryDispSync的计数,然后调用EventControlThread的setVsyncEnabled函数,我们前面已经讲过这个函数的作用——就是打开硬件的VSYNC功能—-我们前面提出了什么时候调用setVsyncEnabled函数疑问,现在这个疑问可以被回答了,这个函数是在屏幕点亮时被调用了。

init中VSync的简单小节

这样我们简单的学习完了init中和VSync有关的一些知识。其实主要的流程代码就是下面的一小段:

 
 
  1. {  
  2. ...  
  3.     // start the EventThread  
  4.     sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,  
  5.             vsyncPhaseOffsetNs, true);  
  6.     mEventThread = new EventThread(vsyncSrc);  
  7.     sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,  
  8.             sfVsyncPhaseOffsetNs, true);  
  9.     mSFEventThread = new EventThread(sfVsyncSrc);  
  10.     mEventQueue.setEventThread(mSFEventThread);  
  11.   
  12.     mEventControlThread = new EventControlThread(this);  
  13.     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);  
  14.   
  15.     // set a fake vsync period if there is no HWComposer  
  16.     if (mHwc->initCheck() != NO_ERROR) {  
  17.         mPrimaryDispSync.setPeriod(16666667);  
  18.     }  
  19. ...  
  20.     // initialize our drawing state  
  21.     mDrawingState = mCurrentState;  
  22.   
  23.     // set initial conditions (e.g. unblank default device)  
  24.     initializeDisplays();  
  25. ...  
  26. }  
  1. 首先就是创建了两个DispSyncSource和EventThread,这两组线程可以各自配置延迟,分别对应渲染和合成。这样渲染和合成就可以在收到真正的VSync信号之后错开执行。EventThread创建之后将会等待VSync信号的通知,一旦收到信号后将会分发给感兴趣的监听者。
  2. mEventQueue(MessageQueue)和EventThread建立连接,实际上就是注册成为了一个监听者。
  3. 创建了一个EventControlThread线程,用以和硬件HWC通信,控制HWC是否生成VSync信号。
  4. 最后mPrimaryDispSync.setPeriod(16666667)是指如果硬件不能生成VSync信号,那么软件将模拟生成,并且生成的周期设置为16.6ms左右。
    5.最后在调用initializeDisplays函数初始化显示的过程中,我们又调用了onScreenAcquired函数,这个函数主要是唤醒了EventThread的等待,重置了mPrimaryDispSync,并且设置mPrimaryHWVsyncEnabled为true,并且通知硬件打开VSYNC通知。

基本流程如下图所示:
此处输入图片的描述
其中红色部分我们会在下一章VSync的接收和处理中再次展开讲解。

onVSyncReceived函数

这样,经过漫长的讲解,我们又从VSync的角度重新分析了SurfaceFlinger的init函数中的一些细节,现在我们终于可以回到这一小节开始之前我们提出的那几个问题:

当Surfaceflinger的收到VSync消息时的onVSyncReceived函数:

 
 
  1. void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {  
  2.     bool needsHwVsync = false;  
  3.     {  
  4.         if (type == 0 && mPrimaryHWVsyncEnabled) {  
  5.             needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);  
  6.         }  
  7.     }  
  8.     if (needsHwVsync) {  
  9.         enableHardwareVsync();  
  10.     } else {  
  11.         disableHardwareVsync(false);  
  12.     }  
  13. }  

这段代码很短,但是相当让人困惑,困惑至少有以下三点:

  1. mPrimaryHWVsyncEnabled是干嘛的,是被什么时候赋值的?
  2. enableHardwareVsync和disableHardwareVsync又起到了什么作用?
  3. mPrimaryDispSync是什么?addResyncSample有什么作用?

现在我们可以尝试来回答上面的这三个疑问了:

  1. mPrimaryHWVsyncEnabled是用来标识主屏幕对应的HWC的VSYNC功能有没有被开启。这个值在SurfaceFlinger创建时被赋值为false,在onScreenAcquired屏幕被点亮时,被设置为true。
  2. enableHardwareVsync所起的作用其实跟我们前面提到的resyncToHardwareVsync函数作用基本一样,也是打开硬件的VSync功能。而disableHardwareVsync自然就是关闭硬件的VSync功能。
       
       
    1. void SurfaceFlinger::enableHardwareVsync() {  
    2.  if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {  
    3.      mPrimaryDispSync.beginResync();  
    4.      mEventControlThread->setVsyncEnabled(true);  
    5.      mPrimaryHWVsyncEnabled = true;  
    6.  }  
    7. }  
  3. mPrimaryDispSync的类型是DispSync(当然这个变量的创建时刻依然有待确认),表示了一个基于硬件VSync信号的同步模型,它会根据从HWComposer来的硬件VSync信号的采样来进行同步。
    了解了上面三个问题之后,我们终于可以来看下这段代码中最重要的一个函数调用—-addResyncSample。
    我们将在下一章的VSync消息的处理一章中详细分析这个函数以及后续消息的处理流程。

总结起来如下图:此处输入图片的描述图中红色部分涉及到了VSync信号的在系统内的传输过程,我们在这一章详细的展开说明。

向Eventhread注册一个事件的监听者——createEventConnection

在SurfaceFlinger的init函数中,我们调用了mEventQueue.setEventThread(mSFEventThread)函数,我们在前面一章中已经提到过,这个函数将SurfaceFlinger的MessageQueue真正和我们刚才创建的EventThread建立起了连接。我们来看下这段代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void MessageQueue::setEventThread(const sp<EventThread>& eventThread)  
  2. {  
  3.     mEventThread = eventThread;  
  4.     mEvents = eventThread->createEventConnection();  
  5.     mEventTube = mEvents->getDataChannel();  
  6.     mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,  
  7.             MessageQueue::cb_eventReceiver, this);  
  8. }  

createEventConnection是将EventThread和MessageQueue建立连接的函数:

  
  
  1. sp<EventThread::Connection> EventThread::createEventConnection() const {  
  2.     return new Connection(const_cast<EventThread*>(this));  
  3. }  
  4. EventThread::Connection::Connection(  
  5.         const sp<EventThread>& eventThread)  
  6.     : count(-1), mEventThread(eventThread), mChannel(new BitTube())  
  7. {  
  8. }  
  9. void EventThread::Connection::onFirstRef() {  
  10.     mEventThread->registerDisplayEventConnection(this);  
  11. }  
  12. status_t EventThread::registerDisplayEventConnection(  
  13.         const sp<EventThread::Connection>& connection) {  
  14.     mDisplayEventConnections.add(connection);  
  15.     mCondition.broadcast();  
  16. }  

我们看这个函数虽然传递了很多次,但是其实逻辑依然很简单易懂。其实无非是这个函数会导致一个Connection类的创建,而这个connection类会被保存在EventThread下的一个容器内。

通过createEventConnection这样一个简单的方法,我们其实就注册了一个事件的监听者,得到了发送VSYNC事件通知的BitTube,然后监控这个BitTube中的套接字,并且指定了收到通知后的回调函数,MessageQueue::cb_eventReceiver。这样一旦VSync信号传来,函数cb_eventReceiver将被调用。

等待事件

继续回到上一章的图中:
此处输入图片的描述
刚才我们分析了创建一个连接,SurfaceFlinger的MessageQueue注册了一个监听者到EventThread中的mDisplayEventConnections容器中,等待event事件到来时被通知。下面我们继续分析一下我们前面一章没有展开说明的另外一个函数:
EventThread中等待事件时的函数waitForEvent。

  
  
  1. // This will return when (1) a vsync event has been received, and (2) there was  
  2. // at least one connection interested in receiving it when we started waiting.  
  3. Vector< sp<EventThread::Connection> > EventThread::waitForEvent(  
  4.         DisplayEventReceiver::Event* event)  
  5. {  
  6.         // Here we figure out if we need to enable or disable vsyncs  
  7.         if (timestamp && !waitForVSync) {  
  8.             // we received a VSYNC but we have no clients  
  9.             // don't report it, and disable VSYNC events  
  10.             disableVSyncLocked();  
  11.         } else if (!timestamp && waitForVSync) {  
  12.             // we have at least one client, so we want vsync enabled  
  13.             // (TODO: this function is called right after we finish  
  14.             // notifying clients of a vsync, so this call will be made  
  15.             // at the vsync rate, e.g. 60fps.  If we can accurately  
  16.             // track the current state we could avoid making this call  
  17.             // so often.)  
  18.             enableVSyncLocked();  
  19.         }  
  20.   
  21.         // note: !timestamp implies signalConnections.isEmpty(), because we  
  22.         // don't populate signalConnections if there's no vsync pending  
  23.         if (!timestamp && !eventPending) {  
  24.             // wait for something to happen  
  25.             if (waitForVSync) {  
  26.                 // This is where we spend most of our time, waiting  
  27.                 // for vsync events and new client registrations.  
  28.                 //  
  29.                 // If the screen is off, we can't use h/w vsync, so we  
  30.                 // use a 16ms timeout instead.  It doesn't need to be  
  31.                 // precise, we just need to keep feeding our clients.  
  32.                 //  
  33.                 // We don't want to stall if there's a driver bug, so we  
  34.                 // use a (long) timeout when waiting for h/w vsync, and  
  35.                 // generate fake events when necessary.  
  36.                 bool softwareSync = mUseSoftwareVSync;  
  37.                 nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);  
  38.                 if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {  
  39.                     if (!softwareSync) {  
  40.                         ALOGW("Timed out waiting for hw vsync; faking it");  
  41.                     }  
  42.                     // FIXME: how do we decide which display id the fake  
  43.                     // vsync came from ?  
  44.                     mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;  
  45.                     mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;  
  46.                     mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);  
  47.                     mVSyncEvent[0].vsync.count++;  
  48.                 }  
  49.             } else {  
  50.                 // Nobody is interested in vsync, so we just want to sleep.  
  51.                 // h/w vsync should be disabled, so this will wait until we  
  52.                 // get a new connection, or an existing connection becomes  
  53.                 // interested in receiving vsync again.  
  54.                 mCondition.wait(mLock);  
  55.             }  
  56.         }  
  57.     } while (signalConnections.isEmpty());  
  58.   
  59.     // here we're guaranteed to have a timestamp and some connections to signal  
  60.     // (The connections might have dropped out of mDisplayEventConnections  
  61.     // while we were asleep, but we'll still have strong references to them.)  
  62.     return signalConnections;  
  63. }  

waitForEvent是一个相当长的函数,我们上文只截取了函数的后半部分,在被删掉的前半部分中,函数主要在处理和EventThread建立起连接的客户端,也就是我们上面提到的通过createEventConnection来于EventThread建立起连接的客户端。
前半部分代码通过计算对两个变量的赋值产生了影响,timestamp非零代表有一个VSync信号需要处理,waitForVSync为true则代表有客户端在等待VSync信号。我们下面来仔细分析下后半部分的代码:

  
  
  1. // Here we figure out if we need to enable or disable vsyncs  
  2. if (timestamp && !waitForVSync) {  
  3.     // we received a VSYNC but we have no clients  
  4.     // don't report it, and disable VSYNC events  
  5.     disableVSyncLocked();  
  6. else if (!timestamp && waitForVSync) {  
  7.     // we have at least one client, so we want vsync enabled  
  8.     // (TODO: this function is called right after we finish  
  9.     // notifying clients of a vsync, so this call will be made  
  10.     // at the vsync rate, e.g. 60fps.  If we can accurately  
  11.     // track the current state we could avoid making this call  
  12.     // so often.)  
  13.     enableVSyncLocked();  
  14. }  

上面这段代码的含义其实注释里面写的很清楚,根据是否需要来决定禁用和开启VSync信号。两个分支的条件也都有注释,第一个分支的含义是收到了VSync但是却没有客户端感兴趣,这个时候我们会选择禁用VSync,另一条分支则是没有收到VSync信号但是有客户端对信号感兴趣,那么这个时候我们会开启VSync。

在上一章中我们已经提到了,真正向硬件发送开关VSync信号的命令的是EventControlThread,那么这里的disableVSyncLocked和enableVSyncLocked的原理是否和EventControlThread一致呢?我们来仔细分析一下这个函数:

  
  
  1. void EventThread::enableVSyncLocked() {  
  2.     if (!mUseSoftwareVSync) {//这个条件会筛掉灭屏的情况  
  3.         // never enable h/w VSYNC when screen is off  
  4.         if (!mVsyncEnabled) {  
  5.             mVsyncEnabled = true;  
  6.             mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));  
  7.             mVSyncSource->setVSyncEnabled(true);  
  8.             mPowerHAL.vsyncHint(true);  
  9.         }  
  10.     }  
  11.     mDebugVsyncEnabled = true;  
  12. }  

上面函数主要调用了VSyncSource的setVSyncEnabled函数:

  
  
  1. virtual void setVSyncEnabled(bool enable) {  
  2.     // Do NOT lock the mutex here so as to avoid any mutex ordering issues  
  3.     // with locking it in the onDispSyncEvent callback.  
  4.     if (enable) {  
  5.         status_t err = mDispSync->addEventListener(mPhaseOffset,  
  6.                 static_cast<DispSync::Callback*>(this));  
  7.         if (err != NO_ERROR) {  
  8.             ALOGE("error registering vsync callback: %s (%d)",  
  9.                     strerror(-err), err);  
  10.         }  
  11.         ATRACE_INT("VsyncOn", 1);  
  12.     } else {  
  13.         status_t err = mDispSync->removeEventListener(  
  14.                 static_cast<DispSync::Callback*>(this));  
  15.         if (err != NO_ERROR) {  
  16.             ALOGE("error unregistering vsync callback: %s (%d)",  
  17.                     strerror(-err), err);  
  18.         }  
  19.         ATRACE_INT("VsyncOn", 0);  
  20.     }  
  21. }  
  22.   
  23. status_t DispSync::addEventListener(nsecs_t phase,  
  24.     const sp<Callback>& callback) {  
  25.     return mThread->addEventListener(phase, callback);  
  26. }  

看到这里我们发现,其实所谓的disableVSyncLocked和enableVSyncLocked禁用开启VSync信号并非真的让硬件停止发送信号,只是向DispSync(里面的DispSyncThread,DispSyncThread在DispSync被创建时启动)删除和添加事件的监听者,通过添加监听者,新的监听者就可以收到来自硬件的VSync消息,而一旦删除,EventThread不再能收到消息,显然对于EventThread来说,也就禁用了VSync消息。

分析完EventThread的disableVSyncLocked和enableVSyncLocked函数,我们回到waitForEvent函数继续分析。剩下的逻辑很简单了:

  
  
  1. // wait for something to happen  
  2.             if (waitForVSync) {  
  3.                 // This is where we spend most of our time, waiting  
  4.                 // for vsync events and new client registrations.  
  5.                 //  
  6.                 // If the screen is off, we can't use h/w vsync, so we  
  7.                 // use a 16ms timeout instead.  It doesn't need to be  
  8.                 // precise, we just need to keep feeding our clients.  
  9.                 //  
  10.                 // We don't want to stall if there's a driver bug, so we  
  11.                 // use a (long) timeout when waiting for h/w vsync, and  
  12.                 // generate fake events when necessary.  
  13.                 bool softwareSync = mUseSoftwareVSync;  
  14.                 nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);  
  15.                 if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {  
  16.                     if (!softwareSync) {  
  17.                         ALOGW("Timed out waiting for hw vsync; faking it");  
  18.                     }  
  19.                     // FIXME: how do we decide which display id the fake  
  20.                     // vsync came from ?  
  21.                     mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;  
  22.                     mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;  
  23.                     mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);  
  24.                     mVSyncEvent[0].vsync.count++;  
  25.                 }  
  26.             } else {  
  27.                 // Nobody is interested in vsync, so we just want to sleep.  
  28.                 // h/w vsync should be disabled, so this will wait until we  
  29.                 // get a new connection, or an existing connection becomes  
  30.                 // interested in receiving vsync again.  
  31.                 mCondition.wait(mLock);  
  32.             }  

代码不长,逻辑也很简单,这里通过mCondition.waitRelative和mCondition.wait开始等待事件的发生了。
终于分析完这里,我们已经注册好了监听者,起好了线程,开始等待VSync的到来了。我们终于可以回到最最开始的问题里面,当VSync信号发出来时,系统到底是怎么处理的?

VSync信号的处理

我们在前面一章也提到了无论是软件方式还是硬件方式,SurfaceFlinger收到VSync信号后,处理函数都是onVSyncReceived函数:

  
  
  1. void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {  
  2.     bool needsHwVsync = false;  
  3.     {  
  4.         if (type == 0 && mPrimaryHWVsyncEnabled) {  
  5.             needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);  
  6.         }  
  7.     }  
  8.     if (needsHwVsync) {  
  9.         enableHardwareVsync();  
  10.     } else {  
  11.         disableHardwareVsync(false);  
  12.     }  
  13. }  

前文中我们也说过这段代码中最重要的一个函数调用—-addResyncSample,下面本文也将从这个函数开始继续VSync的研究。

真正开始处理VSync消息——addResyncSample

  
  
  1. bool DispSync::addResyncSample(nsecs_t timestamp) {  
  2.     size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;  
  3.     mResyncSamples[idx] = timestamp;  
  4.   
  5.     if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {  
  6.         mNumResyncSamples++;  
  7.     } else {  
  8.         mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES;  
  9.     }  
  10.   
  11.     updateModelLocked();  
  12.   
  13.     if (mNumResyncSamplesSincePresent++ > MAX_RESYNC_SAMPLES_WITHOUT_PRESENT) {  
  14.         resetErrorLocked();  
  15.     }  
  16.     if (runningWithoutSyncFramework) {  
  17.         // If we don't have the sync framework we will never have  
  18.         // addPresentFence called.  This means we have no way to know whether  
  19.         // or not we're synchronized with the HW vsyncs, so we just request  
  20.         // that the HW vsync events be turned on whenever we need to generate  
  21.         // SW vsync events.  
  22.         return mThread->hasAnyEventListeners();  
  23.     }  
  24.   
  25.     return mPeriod == 0 || mError > errorThreshold;  
  26. }  

粗略浏览下这个函数,发现前半部分其实在做一些简单的计数统计,重点实现显然是updateModelLocked函数:

  
  
  1. void DispSync::updateModelLocked() {  
  2.     if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {  
  3.         nsecs_t durationSum = 0;  
  4.         for (size_t i = 1; i < mNumResyncSamples; i++) {  
  5.             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;  
  6.             size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;  
  7.             durationSum += mResyncSamples[idx] - mResyncSamples[prev];  
  8.         }  
  9.   
  10.         mPeriod = durationSum / (mNumResyncSamples - 1);  
  11.   
  12.         double sampleAvgX = 0;  
  13.         double sampleAvgY = 0;  
  14.         double scale = 2.0 * M_PI / double(mPeriod);  
  15.         for (size_t i = 0; i < mNumResyncSamples; i++) {  
  16.             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;  
  17.             nsecs_t sample = mResyncSamples[idx];  
  18.             double samplePhase = double(sample % mPeriod) * scale;  
  19.             sampleAvgX += cos(samplePhase);  
  20.             sampleAvgY += sin(samplePhase);  
  21.         }  
  22.   
  23.         sampleAvgX /= double(mNumResyncSamples);  
  24.         sampleAvgY /= double(mNumResyncSamples);  
  25.   
  26.         mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);  
  27.   
  28.         if (mPhase < 0) {  
  29.             mPhase += mPeriod;  
  30.         }  
  31.   
  32.         if (traceDetailedInfo) {  
  33.             ATRACE_INT64("DispSync:Period", mPeriod);  
  34.             ATRACE_INT64("DispSync:Phase", mPhase);  
  35.         }  
  36.   
  37.         mThread->updateModel(mPeriod, mPhase);  
  38.     }  
  39. }  

不得不说,前面大段的数学计算让人有些困惑,我们暂且跳过,先分析下主线流程,也就是mThread->updateModel(mPeriod, mPhase)这个调用:

DispSyncThread.updateModel的用途

  
  
  1. void updateModel(nsecs_t period, nsecs_t phase) {  
  2.     Mutex::Autolock lock(mMutex);  
  3.     mPeriod = period;  
  4.     mPhase = phase;  
  5.     mCond.signal();  
  6. }  

updateModel是DispSyncThread类的函数,这个函数本身代码很短,其实它的主要作用是mCond.signal发送一个信号给等待中的线程。那么究竟是谁在等待这个条件呢?
其实等待这个条件的正是DispSyncThread的循环函数:

  
  
  1. virtual bool threadLoop() {  
  2.       status_t err;  
  3.       nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);  
  4.       nsecs_t nextEventTime = 0;  
  5.       while (true) {  
  6.           Vector<CallbackInvocation> callbackInvocations;  
  7.           nsecs_t targetTime = 0;  
  8.           { // Scope for lock  
  9.               Mutex::Autolock lock(mMutex);  
  10.               if (mStop) {  
  11.                   return false;  
  12.               }  
  13.               if (mPeriod == 0) {  
  14.                   err = mCond.wait(mMutex);  
  15.                   if (err != NO_ERROR) {  
  16.                       ALOGE("error waiting for new events: %s (%d)",  
  17.                               strerror(-err), err);  
  18.                       return false;  
  19.                   }  
  20.                   continue;  
  21.               }  
  22.               nextEventTime = computeNextEventTimeLocked(now);  
  23.               targetTime = nextEventTime;  
  24.               bool isWakeup = false;  
  25.               if (now < targetTime) {  
  26.                   err = mCond.waitRelative(mMutex, targetTime - now);  
  27.                   if (err == TIMED_OUT) {  
  28.                       isWakeup = true;  
  29.                   } else if (err != NO_ERROR) {  
  30.                       ALOGE("error waiting for next event: %s (%d)",  
  31.                               strerror(-err), err);  
  32.                       return false;  
  33.                   }  
  34.               }  
  35.               now = systemTime(SYSTEM_TIME_MONOTONIC);  
  36.               if (isWakeup) {  
  37.                   mWakeupLatency = ((mWakeupLatency * 63) +  
  38.                           (now - targetTime)) / 64;  
  39.                   if (mWakeupLatency > 500000) {  
  40.                       // Don't correct by more than 500 us  
  41.                       mWakeupLatency = 500000;  
  42.                   }  
  43.                   if (traceDetailedInfo) {  
  44.                       ATRACE_INT64("DispSync:WakeupLat", now - nextEventTime);  
  45.                       ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);  
  46.                   }  
  47.               }  
  48.               callbackInvocations = gatherCallbackInvocationsLocked(now);  
  49.           }  
  50.           if (callbackInvocations.size() > 0) {  
  51.               fireCallbackInvocations(callbackInvocations);  
  52.           }  
  53.       }  
  54.       return false;  
  55.   }  

大量的时间相关的计算和状态的转变我们不再深入研究,我们来看下这个线程被通知唤醒之后做的两个主要的函数的处理,gatherCallbackInvocationsLocked和fireCallbackInvocations。

gatherCallbackInvocationsLocked的代码其实很简单:

  
  
  1. Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {  
  2.     Vector<CallbackInvocation> callbackInvocations;  
  3.     nsecs_t ref = now - mPeriod;  
  4.     for (size_t i = 0; i < mEventListeners.size(); i++) {  
  5.         nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],  
  6.                 ref);  
  7.         if (t < now) {  
  8.             CallbackInvocation ci;  
  9.             ci.mCallback = mEventListeners[i].mCallback;  
  10.             ci.mEventTime = t;  
  11.             callbackInvocations.push(ci);  
  12.             mEventListeners.editItemAt(i).mLastEventTime = t;  
  13.         }  
  14.     }  
  15.     return callbackInvocations;  
  16. }  

其实就是从mEventListeners取出之前注册的事件监听者,放入callbackInvocations中,等待后面的调用。至于监听者从何处而来?我们在前面已经给出了分析,在waitforevent时通过enableVSyncLocked注册的。

继续看下fireCallbackInvocations函数:

  
  
  1. void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {  
  2.     for (size_t i = 0; i < callbacks.size(); i++) {  
  3.         callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);  
  4.     }  
  5. }`  

我们目前只分析主线的走向,接下来调用了DispSyncSource的onDispSyncEvent在:

  
  
  1.     virtual void onDispSyncEvent(nsecs_t when) {  
  2.         sp<VSyncSource::Callback> callback;  
  3.         {  
  4.             callback = mCallback;  
  5.         }  
  6.         if (callback != NULL) {  
  7.             callback->onVSyncEvent(when);  
  8.         }  
  9.     }  
  10. void EventThread::onVSyncEvent(nsecs_t timestamp) {  
  11.     Mutex::Autolock _l(mLock);  
  12.     mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;  
  13.     mVSyncEvent[0].header.id = 0;  
  14.     mVSyncEvent[0].header.timestamp = timestamp;  
  15.     mVSyncEvent[0].vsync.count++;  
  16.     mCondition.broadcast();  
  17. }  

我们看到这里mCondition.broadcas发出了命令,那么EventThread中waitforEvent的等待就会被唤醒。而一旦唤醒,我们就回到了EventThread的loop中,我们来看下代码:

  
  
  1. bool EventThread::threadLoop() {  
  2.     DisplayEventReceiver::Event event;  
  3.     Vector< sp<EventThread::Connection> > signalConnections;  
  4.     signalConnections = waitForEvent(&event);  
  5.   
  6.     // dispatch events to listeners...  
  7.     const size_t count = signalConnections.size();  
  8.     for (size_t i=0 ; i<count ; i++) {  
  9.         const sp<Connection>& conn(signalConnections[i]);  
  10.         // now see if we still need to report this event  
  11.         status_t err = conn->postEvent(event);  
  12.         if (err == -EAGAIN || err == -EWOULDBLOCK) {  
  13.             // The destination doesn't accept events anymore, it's probably  
  14.             // full. For now, we just drop the events on the floor.  
  15.             // FIXME: Note that some events cannot be dropped and would have  
  16.             // to be re-sent later.  
  17.             // Right-now we don't have the ability to do this.  
  18.             ALOGW("EventThread: dropping event (%08x) for connection %p",  
  19.                     event.header.type, conn.get());  
  20.         } else if (err < 0) {  
  21.             // handle any other error on the pipe as fatal. the only  
  22.             // reasonable thing to do is to clean-up this connection.  
  23.             // The most common error we'll get here is -EPIPE.  
  24.             removeDisplayEventConnection(signalConnections[i]);  
  25.         }  
  26.     }  
  27.     return true;  
  28. }  

这里主要就是通过conn->postEvent来分发事件:

  
  
  1. status_t EventThread::Connection::postEvent(  
  2.         const DisplayEventReceiver::Event& event) {  
  3.     ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);  
  4.     return size < 0 ? status_t(size) : status_t(NO_ERROR);  
  5. }  
  6. ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,  
  7.         Event const* events, size_t count)  
  8. {  
  9.     return BitTube::sendObjects(dataChannel, events, count);  
  10. }  

其实看到这里的BitTube我们就明白了,在本文开始时候我们提到:

通过createEventConnection这样一个简单的方法,我们其实就注册了一个事件的监听者,得到了发送VSYNC事件通知的BitTube,然后监控这个BitTube中的套接字,并且指定了收到通知后的回调函数,MessageQueue::cb_eventReceiver。这样一旦VSync信号传来,函数cb_eventReceiver将被调用。

所以我们这里可以来看看MessageQueue::cb_eventReceiver函数了:

  
  
  1. int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {  
  2.     MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);  
  3.     return queue->eventReceiver(fd, events);  
  4. }  
  5.   
  6. int MessageQueue::eventReceiver(int fd, int events) {  
  7.     ssize_t n;  
  8.     DisplayEventReceiver::Event buffer[8];  
  9.     while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {  
  10.         for (int i=0 ; i<n ; i++) {  
  11.             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {  
  12.                 mHandler->dispatchInvalidate();  
  13.                 break;  
  14.             }  
  15.         }  
  16.     }  
  17.     return 1;  
  18. }  

我们看到收到消息之后MessageQueue对消息进行了分发,我们目前走的是dispatchInvalidate。

  
  
  1. void MessageQueue::Handler::dispatchInvalidate() {  
  2.     if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {  
  3.         mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));  
  4.     }  
  5. }  
  6.   
  7. void MessageQueue::Handler::handleMessage(const Message& message) {  
  8.     switch (message.what) {  
  9.         case INVALIDATE:  
  10.             android_atomic_and(~eventMaskInvalidate, &mEventMask);  
  11.             mQueue.mFlinger->onMessageReceived(message.what);  
  12.             break;  
  13.         case REFRESH:  
  14.             android_atomic_and(~eventMaskRefresh, &mEventMask);  
  15.             mQueue.mFlinger->onMessageReceived(message.what);  
  16.             break;  
  17.         case TRANSACTION:  
  18.             android_atomic_and(~eventMaskTransaction, &mEventMask);  
  19.             mQueue.mFlinger->onMessageReceived(message.what);  
  20.             break;  
  21.     }  
  22. }  
  23.   
  24. void SurfaceFlinger::onMessageReceived(int32_t what) {  
  25.     ATRACE_CALL();  
  26.     switch (what) {  
  27.     case MessageQueue::TRANSACTION:  
  28.         handleMessageTransaction();  
  29.         break;  
  30.     case MessageQueue::INVALIDATE:  
  31.         handleMessageTransaction();  
  32.         handleMessageInvalidate();  
  33.         signalRefresh();  
  34.         break;  
  35.     case MessageQueue::REFRESH:  
  36.         handleMessageRefresh();  
  37.         break;  
  38.     }  
  39. }  

到了这里,就进入了SurfaceFlinger的处理流程,我们看到对于INVALIDATE的消息,实际上系统在处理过程中实际还是会发送一个Refresh消息。
这后面的处理过程,我会在博客后面的文章中详细讲解。

总结

我们用了两小节的篇幅来讲解了VSync在android系统中的作用,生成以及传递。详细说明了从VSync软硬件的生成,一直到事件如何做为一个INVALIDATE消息传递给了Surfaceflinger处理。我们再来回顾一下整体的流程图:
此处输入图片的描述


  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值