Android 4.4对VSync机制的一个改进

Android4.4中,对VSync机制的实现进行了一些修改,但是总体过程还是一样:

1. HWComposer将底层硬件产生的VSync报告给SurfaceFlinger

2. SurfaceFlingerVSync又通知给EventThread线程。

3. EventThread收到VSync事件后,调用相应的回调函数。


总体来看,主要的修改有如下几点:

1. 引入了VSync Event Model,通过该模型,来充当VSync的事件源,它的VSync时间戳当然是基于硬件为参考的,具体实现在DispSync类中,它会周期性的调用注册到这个对象上的回调函数。

2. SurfaceFlinger新定义了一个DispSyncSource类,该类继承自VSyncSourceDispSync::Callback,实现了DispSync::Callback定义的回调接口onDispSyncEvent,在该接口里面,会调用注册到DispSyncSource的回调函数接口VSyncSource::Callback对象,并调用其实现的onVSyncEvent函数接口。

3. EventThread的主要改动是构造函数接受一个VSynSource的智能指针对象,其本身也实现了VSyncSource::Callback接口,即其本身也是一个VSyncSource::Callback对象。因为它会将自己注册给DispSyncSource对象作为他的一个周期性回调函数,所以会调用它实现的onVSyncEvent函数。

4. 开启和关闭硬件VSync功能放在一个单独的线程中,叫EventControlThread


通过SurfaceFlingeronVSyncReceived代码可以看到:

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类,这是一个重大的改变,它降低了SurfaceFlingerEventThread的逻辑耦合,它的定义如下:

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类调用DispSyncSourceonDispSyncEvent,在该方法中会调用EventThreadonVSyncEvent函数。


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

3. beginResync(), addResyncSample(),endResync()

        当Vsync事件模型时间戳与硬件对应的Fence对象的时间戳偏离后,需要依次调用上述三个接口来同步,只要addResyncSample()返回false,就表明已经同步完成,此时VSync 事件模型与硬件Vsync事件又保持一致了。 


         刚开机的时候,底层硬件Vsync是打开的,它会周期性产生Vsync事件,HWComposer会回调SurfaceFlingeronVSyncReceived()接口,在这个接口里面,每次调用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不能关闭,会一直保持打开状态。



     

你可能感兴趣的:(Android研究)