Android VSync信号产生过程源码分析

来源:互联网 发布:linux怎么配置jdk 编辑:程序博客网 时间:2024/06/17 14:17

在上一篇Android Project Butter分析中介绍了Android4.1通过引入VSync机制来改善显示效果,并分析了VSync机制的原理。本文主要分析VSync信号的产生过程。VSync信号产生有两种方式,一种是硬件中断产生,另一种是使用软件模拟产生,至于使用何种方式产生VSync信号,就和硬件系统配置有关。在Android4.1以后的版本中,定义了HWComposer硬件抽象模块来负责产生VSync信号。HWComposer硬件抽象层定义:

hardware\libhardware\modules\hwcomposer\hwcomposer.cpp

hwc_module_t HAL_MODULE_INFO_SYM = {    common: {        tag: HARDWARE_MODULE_TAG,        version_major: 1,        version_minor: 0,        id: HWC_HARDWARE_MODULE_ID,        name: "Sample hwcomposer module",        author: "The Android Open Source Project",        methods: &hwc_module_methods,    }};
注册的硬件抽象模块方法定义如下:

static struct hw_module_methods_t hwc_module_methods = {    open: hwc_device_open};

关于为硬件抽象模块HWComposer定义的数据结构之间的关系如下下图所示:


在初始化DisplayHardware对象时,会创建一个HWComposer对象:

void DisplayHardware::init(uint32_t dpy){...    // initialize the H/W composer    mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod);    if (mHwc->initCheck() == NO_ERROR) {        mHwc->setFrameBuffer(mDisplay, mSurface);    }}
这里使用SurfaceFlinger,DisplayHardware对象及屏幕刷新周期来构造HWComposer对象,HWComposer的构造过程如下:

frameworks\native\services\surfaceflinger\DisplayHardware\HWComposer.cpp

HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger,EventHandler& handler,nsecs_t refreshPeriod)    : mFlinger(flinger),      mModule(0), mHwc(0), mList(0), mCapacity(0),      mNumOVLayers(0), mNumFBLayers(0),      mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE),      mEventHandler(handler),      mRefreshPeriod(refreshPeriod),      mVSyncCount(0), mDebugForceFakeVSync(false){    char value[PROPERTY_VALUE_MAX];    property_get("debug.sf.no_hw_vsync", value, "0");    mDebugForceFakeVSync = atoi(value);//是否需要软件模拟VSync    bool needVSyncThread = false;//加载HWComposer硬件抽象模块    int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);    ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);    if (err == 0) {//打开HWComposer硬件抽象模块        err = hwc_open(mModule, &mHwc);        if (err == 0) {//打开成功,注册回调函数            if (mHwc->registerProcs) {                mCBContext.hwc = this;                mCBContext.procs.invalidate = &hook_invalidate;                mCBContext.procs.vsync = &hook_vsync;                mHwc->registerProcs(mHwc, &mCBContext.procs);                memset(mCBContext.procs.zero, 0, sizeof(mCBContext.procs.zero));            }            if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) {                if (mDebugForceFakeVSync) {                    // make sure to turn h/w vsync off in "fake vsync" mode                    mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0);                }            } else {                needVSyncThread = true;            }        }    } else {        needVSyncThread = true;    }//如果HWComposer硬件抽象模块打开失败或者HWComposer硬件抽象模块的版本小于HWC_DEVICE_API_VERSION_0_3,则采用软件模拟产生VSync信号    if (needVSyncThread) {        //创建VSync产生线程VSyncThread        mVSyncThread = new VSyncThread(*this);    }}

在构造HWComposer对象时,选择了VSync信号产生方式:1.硬件产生;2.软件模拟产生;假如当前系统可以成功加载HWC_HARDWARE_MODULE_ID=hwcomposer,并且通过这个库能顺利打开设备(hwc_composer_device_t),并且其版本号又大于HWC_DEVICE_API_VERSION_0_3的话,我们就采用硬件方式产生VSync,否则需要创建一个新的VSync线程来模拟产生信号。


1.硬件产生VSync信号过程


Android定义了hwcomposer硬件抽象模块来负责产生VSync信号,因此在使用硬件方式产生VSync信号时,需要首先加载并打开hwcomposer硬件抽象模块。硬件抽象模块的加载过程已经在Android硬件抽象Hardware库加载过程源码分析详细分析了,因此在这里只介绍hwcomposer硬件模块的打开过程:
err = hwc_open(mModule, &mHwc);
mModule为hw_module_t类型变量,用于描述hwcomposer硬件抽象模块,参数mHwc的类型为hwc_composer_device_t,该结构用于描述hwcomposer硬件设备。
static inline int hwc_open(const struct hw_module_t* module,        hwc_composer_device_t** device) {    return module->methods->open(module,            HWC_HARDWARE_COMPOSER, (struct hw_device_t**)device);}
在定义hwcomposer硬件抽象层时,注册了该硬件抽象模块的打开回调函数hwc_device_open,其实现过程如下:
static int hwc_device_open(const struct hw_module_t* module, const char* name,struct hw_device_t** device){    int status = -EINVAL;    if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {        struct hwc_context_t *dev;        dev = (hwc_context_t*)malloc(sizeof(*dev));        /* initialize our state here */        memset(dev, 0, sizeof(*dev));        /* initialize the procs */        dev->device.common.tag = HARDWARE_DEVICE_TAG;        dev->device.common.version = 0;        dev->device.common.module = const_cast<hw_module_t*>(module);        dev->device.common.close = hwc_device_close;        dev->device.prepare = hwc_prepare;        dev->device.set = hwc_set;        *device = &dev->device.common;        status = 0;    }    return status;}
打开hwcomposer硬件模块过程实际上是创建一个hwc_context_t对象,同时将该模块的回调函数注册到hwc_context_t对象中,如果mHwc->registerProcs不为空的话,我们注册硬件回调mCBContext.procs。当有事件产生时,比如vsync或者invalidate,硬件模块将分别通过procs.vsync和procs.invalidate来通知HWComposer。在这里可以创建一个线程专门负责响应VSync中断:
bool VSyncThread::threadLoop() {    { // scope for lock        Mutex::Autolock _l(mLock);        while (!mEnabled) {            mCondition.wait(mLock);        }    }//进入FrameBuffer驱动等待VSync中断到来    if (ioctl(mFbFd, FBIO_WAITFORVSYNC, NULL) == -1)  {          ALOGE("fail to wait vsync , mFbFd:%d" , mFbFd);      }else{    if(!mDev->procs || !mDev->procs->vsync){  ALOGW("device procs or vsync is null procs:%x , vsync:%x", mDev->procs , mDev->procs->vsync);  return true;  }  //调用VSync回调函数      mDev->procs->vsync(mDev->procs, 0, systemTime(CLOCK_MONOTONIC));      }      return true;}
在该线程运行过程中通过ioctl系统调用进入到fb驱动等待VSync中断,如果VSync中断到来,则ioctl函数从驱动中返回。同时如果注册了VSync回调处理函数,则调用该回调函数来响应VSync信号。在前面构造HWComposer对象时,我们已经注册了VSync中断回调函数为hook_vsync,该函数的实现如下:
void HWComposer::hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp) {    reinterpret_cast<cb_context *>(procs)->hwc->vsync(dpy, timestamp);}
在该函数里调用HWComposer对象的vsync函数来出来响应VSync中断
void HWComposer::vsync(int dpy, int64_t timestamp) {    ATRACE_INT("VSYNC", ++mVSyncCount&1);    mEventHandler.onVSyncReceived(dpy, timestamp);}
mEventHandler为DisplayHardware对象,这里又将VSync中断信号交给DisplayHardware对象处理,DisplayHardware继承于EventHandler类,并实现了该类的虚方法onVSyncReceived,这里调用DisplayHardware对象的onVSyncReceived函数来处理VSync中断信号。关于VSync信号的处理在稍后介绍,到此硬件产生VSync信号的过程就完成了。

2.软件模拟产生VSync信号过程


在构造HWComposer对象时,如果打开hwcomposer硬件抽象模块失败的话就使用软件方式模拟产生VSync信号,软件模拟产生过程就是通过一个线程间隔一段时间调用一次VSync回调函数,从而模拟VSync信号中断效果。首先创建一个专门用于产生VSync信号的线程:
HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)    : mHwc(hwc), mEnabled(false),      mNextFakeVSync(0),      mRefreshPeriod(hwc.mRefreshPeriod){}
VSyncThread继承于RefBase类,该对象第一次强引用自动调用onFirstRef()函数,在该函数中启动线程
void HWComposer::VSyncThread::onFirstRef() {    run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);}
VSyncThread线程的执行过程如下:
bool HWComposer::VSyncThread::threadLoop() {    { // scope for lock        Mutex::Autolock _l(mLock);        while (!mEnabled) {//VSyncThread线程启动后并不立即产生VSync信号,只有通过调用setEnabled函数使能VSync信号后,该线程才往下执行,从而产生VSync信号            mCondition.wait(mLock);        }    }    const nsecs_t period = mRefreshPeriod;//VSync信号的产生间隔时间,屏幕刷新时间    const nsecs_t now = systemTime(CLOCK_MONOTONIC);    nsecs_t next_vsync = mNextFakeVSync;//下一次VSync信号产生时间    nsecs_t sleep = next_vsync - now; //需要休眠的时间间隔    if (sleep < 0) {        // we missed, find where the next vsync should be        sleep = (period - ((now - next_vsync) % period));        next_vsync = now + sleep;    }    mNextFakeVSync = next_vsync + period;    struct timespec spec;    spec.tv_sec  = next_vsync / 1000000000;    spec.tv_nsec = next_vsync % 1000000000;    int err;    do {        err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);    } while (err<0 && errno == EINTR);//每隔屏幕刷新时间间隔调用一次onVSyncReceived函数    if (err == 0) {        mHwc.mEventHandler.onVSyncReceived(0, next_vsync);    }//一次信号产生完成后,函数直接返回true,当threadLoop返回值为“真”时,它将被系统再一次调用,从而循环起来。    return true;}
mEnabled用于控制是否产生VSync信号。当希望关闭VSync信号发生源时,调用VSyncThread::setEnabled(false),否则传入true。mEnabled为false时,VSyncThread就处于等待状态,直到再次使能这个线程。
VSync产生步骤:
1)计算下一次产生VSync信号的时间
2)线程进入休眠
3)休眠时间到了后,发出VSync信号了,通知感兴趣的人
4)循环往复
屏幕刷新周期计算公式:mRefreshPeriod = nsecs_t(1e9 / mRefreshRate);如果屏幕刷新频率mRefreshRate为60Hz的话,mRefreshPeriod就差不多是16ms。mNextFakeVSync代表下一次产生信号的时间点,mNextFakeVSync代表的是下一次threadLoop需要用到的时间点,所以首先将next_vsync=mNextFakeVSync。然后计算产生下一次VSync信号需要睡眠的时间:sleep = (period - ((now - next_vsync) % period));

当休眠时间到了后,函数跳出while循环,表示VSync信号产生的时刻到了,这时就调用成员变量mEventHandler的onVSyncReceived函数来响应VSync信号,软件模拟产生VSync信号的间隔时间就是屏幕刷新周期。成员变量mEventHandler的类型为EventHandler,在HWComposer的构造函数中,该变量指向DisplayHardware对象,因此这里调用的是DisplayHardware对象的onVSyncReceived函数来处理VSync中断。这里可以看出,无论是硬件产生VSync还是软件模拟产生VSync信号,最终都是交给DisplayHardware对象处理:

void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) {    sp<VSyncHandler> handler;    { // scope for the lock        Mutex::Autolock _l(mLock);        mLastHwVSync = timestamp;        if (mVSyncHandler != NULL) {            handler = mVSyncHandler.promote();        }    }    if (handler != NULL) {        handler->onVSyncReceived(dpy, timestamp);    }}

DisplayHardware的成员变量mVSyncHandler的类型为VSyncHandler,EventThread类继承于VSyncHandler类,在EventThread的onFirstRef()函数中,通过调用DisplayHardware的setVSyncHandler函数将构造的EventThread对象保存到DisplayHardware的成员变量mVSyncHandler中
void EventThread::onFirstRef() {    mHw.setVSyncHandler(this);    ...}
因此DisplayHardware的成员变量mVSyncHandler实际指向的是EventThread对象。
void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) {    Mutex::Autolock _l(mLock);    mVSyncHandler = handler;}
由此可以看出,对VSync的处理又被DisplayHardware对象转交给了EventThread来完成。EventThread是一个线程类,该线程专门负责分发VSync信号。
void EventThread::onVSyncReceived(int, nsecs_t timestamp) {    Mutex::Autolock _l(mLock);    mVSyncTimestamp = timestamp;    mCondition.broadcast();}
VSync信号产生后,仅仅简单地打开线程互斥量,从而唤醒EventThread线程,让EventThread线程分发VSync信号到来事件给所有已经注册的连接。到此关于VSync信号的产生过程就介绍完了。

原创粉丝点击