在上一篇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信号过程
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::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)循环往复
当休眠时间到了后,函数跳出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);
}
}
void EventThread::onFirstRef() {
mHw.setVSyncHandler(this);
...
}
void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) {
Mutex::Autolock _l(mLock);
mVSyncHandler = handler;
}
void EventThread::onVSyncReceived(int, nsecs_t timestamp) {
Mutex::Autolock _l(mLock);
mVSyncTimestamp = timestamp;
mCondition.broadcast();
}