在Android4.4中,对VSync机制的实现进行了一些修改,但是总体过程还是一样:
1. HWComposer将底层硬件产生的VSync报告给SurfaceFlinger
2. SurfaceFlinger将VSync又通知给EventThread线程。
3. EventThread收到VSync事件后,调用相应的回调函数。
总体来看,主要的修改有如下几点:
1. 引入了VSync Event Model,通过该模型,来充当VSync的事件源,它的VSync时间戳当然是基于硬件为参考的,具体实现在DispSync类中,它会周期性的调用注册到这个对象上的回调函数。
2. SurfaceFlinger新定义了一个DispSyncSource类,该类继承自VSyncSource和DispSync::Callback,实现了DispSync::Callback定义的回调接口onDispSyncEvent,在该接口里面,会调用注册到DispSyncSource的回调函数接口VSyncSource::Callback对象,并调用其实现的onVSyncEvent函数接口。
3. EventThread的主要改动是构造函数接受一个VSynSource的智能指针对象,其本身也实现了VSyncSource::Callback接口,即其本身也是一个VSyncSource::Callback对象。因为它会将自己注册给DispSyncSource对象作为他的一个周期性回调函数,所以会调用它实现的onVSyncEvent函数。
4. 开启和关闭硬件VSync功能放在一个单独的线程中,叫EventControlThread。
通过SurfaceFlinger的onVSyncReceived代码可以看到:
void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
bool needsHwVsync = false;
{ // Scope for the lock
Mutex::Autolock _l(mHWVsyncLock);
if (type == 0 && mPrimaryHWVsyncEnabled) {
needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
}
}
if (needsHwVsync) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
}
从代码可知,底层硬件不用周期性地产生VSync信号,而是按需产生。这是一个重要的优化。这一切都与DispSync类有关。 每次从底层收到一个硬件产生的VSync事件,都会进行判断,是否有必要继续产生硬件VSync事件,只有当它认为与硬件VSync事件有偏离时(即时间戳与硬件对应的Fence对象上的时间戳偏移超出预设的值时),才需要启用硬件产生VSync事件,否则,它就可以代表底层的VSync事件,无需硬件产生VSync事件,从而达到省电的目的。对于SurfaceFlinger,EventThread之间消息的传递流程,大体与4.3没有太多变化,所以本文重点关注DispSync及其所代表的VSync事件模型的原理。
1. VSyncSource类分析
Android4.4引入了VSyncSource类,这是一个重大的改变,它降低了SurfaceFlinger与EventThread的逻辑耦合,它的定义如下:
class VSyncSource : public virtual RefBase {
public:
class Callback: public virtual RefBase {
public:
virtual ~Callback() {}
virtual void onVSyncEvent(nsecs_t when) = 0;
};
virtual ~VSyncSource() {}
virtual void setVSyncEnabled(bool enable) = 0;
virtual void setCallback(const sp& callback) = 0;
};
顾名思义,它代表了一个Vsync源,EventThread类目前直接通过VSyncSource获取VSync事件信息。所以,理论上,只有维护好VSync源,EventThread就会源源不断地收到VSync事件,而至于VSync源是否依赖于底层硬件真实的VSync事件信号,则对EventThread来说,是完全透明的。
另外,VSyncSource是一个纯虚类,在SurfaceFlinger中,定义了一个内部类DispSyncSource,该类实际上是通过DispSync类定义的事件模型来维护一个VSync事件源。当有VSync事件需要上报给EventThread类处理时,则会有如下的调用过程:
DispSync类会通过DispSyncThread类调用DispSyncSource的onDispSyncEvent,在该方法中会调用EventThread的onVSyncEvent函数。
2. DispSync
DispSync维护了一个这样的模型(VSync事件模型):利用显示设备的硬件VSync事件周期性的特征,在硬件Vsync事件特定的偏移处周期性地执行回调函数。即只要显示设备的Vsync硬件事件周期性地到来,DispSync就会在Vsync事件到来的特定时间偏移点,执行相应的回调函数。具体实现是通过addResyncSample方法向DispSync对象喂连续的硬件事件时间戳。
通过使用传递给DispSync对象的一系列Fence对象的时间戳,来判定是否启用该模型。
这些Fence对象的时间戳对应于底层硬件Vsync事件时间戳,但是它们不一定是连续的硬件Vsync 时间戳。如果该方法认为当前模型精确地代表了硬件事件时间戳,它将返回false,表明不需要继续进行同步了。
先简单看下DispSync类的定义:
class DispSync {
public:
class Callback: public virtual RefBase {
public:
virtual ~Callback() {};
virtual void onDispSyncEvent(nsecs_t when) = 0;
};
...
bool addPresentFence(const sp& fence);
...
void beginResync();
bool addResyncSample(nsecs_t timestamp);
void endResync();
}
1. 定义了一个内部接口类,Callback,方法接口名称:onDispSyncEvent, DispSync对象会周期性地调用此函数。
2. addPresentFence(constsp
3. beginResync(), addResyncSample(),endResync()。
当Vsync事件模型时间戳与硬件对应的Fence对象的时间戳偏离后,需要依次调用上述三个接口来同步,只要addResyncSample()返回false,就表明已经同步完成,此时VSync 事件模型与硬件Vsync事件又保持一致了。
刚开机的时候,底层硬件Vsync是打开的,它会周期性产生Vsync事件,HWComposer会回调SurfaceFlinger的onVSyncReceived()接口,在这个接口里面,每次调用addResyncSample()使Vsync 事件模型时间戳与硬件对应的Fence对象的时间戳趋于同步,当返回true时,此时表明同步已经完成,会关闭底层的VSync事件。底层不再会周期性地调用onVSyncReceived()接口。
另一方面,在每次叠图后,会调用postComposition(), 在该函数中,每次会调用addPresentFence()检查Vsync事件模型与硬件对应的Fence对象的时间戳是否有偏移,当返回true, 表明需要进行同步,此时会开启硬件VSync。
void SurfaceFlinger::postComposition()
{
...
const HWComposer& hwc = getHwComposer();
sp presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
if (presentFence->isValid()) {
if (mPrimaryDispSync.addPresentFence(presentFence)) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
}
if (runningWithoutSyncFramework) {
const sp hw(getDefaultDisplayDevice());
if (hw->isScreenAcquired()) {
enableHardwareVsync();
}
}
...
}
另外,从代码中也可以发现,当缺少Android Sync框架的支持时,则硬件VSync不能关闭,会一直保持打开状态。