您的位置:首页 > 移动开发 > Android开发

Android 4.4对VSync机制的一个改进

2015-03-11 21:48 232 查看
在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>& 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>& fence);
...
void beginResync();

bool addResyncSample(nsecs_t timestamp);

void endResync();
}


1. 定义了一个内部接口类,Callback,方法接口名称:onDispSyncEvent, DispSync对象会周期性地调用此函数。

2. addPresentFence(constsp<Fence>& fence),引函数主要用于验证当前的VSync模型是否正常,即有没有偏离实际的硬件VSync时间戳。当返回值为true时,表明当前Vsync Event模型已经与硬件Vsync事件偏离,需要重新同步。

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<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
if (presentFence->isValid()) {
if (mPrimaryDispSync.addPresentFence(presentFence)) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
}
if (runningWithoutSyncFramework) {
const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (hw->isScreenAcquired()) {
enableHardwareVsync();
}
}
...

}


另外,从代码中也可以发现,当缺少Android Sync框架的支持时,则硬件VSync不能关闭,会一直保持打开状态。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: