61阅读

数字信号处理系统-GUI系统之SurfaceFlinger(12)VSync信号的产生和处理

发布时间:2017-11-27 所属栏目:移动通信原理与系统

一 : GUI系统之SurfaceFlinger(12)VSync信号的产生和处理

英雄会第四届在线编程大赛·线上初赛:带通配符的数2014开源技术大会(读书汇)CSDN博客“我的IT成长路”活动 OpenStack企业应用之路浅析

GUI系统之SurfaceFlinger(12)VSync信号的产生和处理

分类: Android专栏 2013-05-21 13:51 2741人阅读 评论(2) 收藏 举报

目录(?)[+]

文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。

转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/

GUI系统之SurfaceFlinger章节目录:

blog.csdn.net/uiop78uiop78/article/details/8954508

1.1 VSync的产生和处理

前面小节ProjectButter中我们学习了Android 4.1显示系统中的新特性,其中一个就是加入了VSync同步。我们从理论的角度分析了采用这一机制的必要性和运作机理,那么SurfaceFlinger具体是如何实施的呢?

先来想一下有哪些东西要考虑:

·VSync信号的产生和分发

如果有硬件主动发出这一信号,那是最好的了;否则就得通过软件定时模拟来产生

·VSync信号的处理

当信号产生后,SurfaceFlinger如何在最短的时间内响应,具体处理流程是怎么样子的

1.1.1 VSync信号的产生和分发

在Android源码surfaceflinger目录下有一个displayhardware文件夹,其中HWComposer的主要职责之一,就是用于产生VSync信号。

/*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)

{

charvalue[PROPERTY_VALUE_MAX];

property_get("debug.sf.no_hw_vsync", value, "0"); //系统属性

mDebugForceFakeVSync =atoi(value);

bool needVSyncThread =false;//是否需要软件模拟VSync

int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);//加载HAL模块

if (err == 0) {

err = hwc_open(mModule, &mHwc);//打开module

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) {//用于调试

mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0);

}

} else {//有可能支持VSync的硬件模块是这个版本以后才加入的,老版本仍然需要软件模拟

needVSyncThread = true;

}

}

} else {

needVSyncThread =true; //硬件模块打开失败,只能用软件模拟

}

if (needVSyncThread) {

mVSyncThread = new VSyncThread(*this);//创建一个产生VSync信号的线程

}

}

这个函数的核心就是决定VSync的“信号发生源”——硬件或者软件模拟。

假如当前系统可以成功加载HWC_HARDWARE_MODULE_ID=“hwcomposer”,并且通过这个库模块能顺利打开设备(hwc_composer_device_t),其版本号又大于HWC_DEVICE_API_VERSION_0_3的话,我们就采用“硬件源”(此时needVSyncThread为false),否则需要创建一个新的VSync线程来模拟产生信号。

(1)硬件源

如果mHwc->registerProcs不为空的话,我们注册硬件回调mCBContext.procs。定义如下:

struct cb_context{

callbacksprocs;

HWComposer*hwc;

};

调用registerProcs()时,传入的参数是&mCBContext.procs。后期当有事件产生时,比如vsync或者invalidate,硬件模块将分别通过procs.vsync和procs.invalidate来通知HWComposer。

void HWComposer::hook_vsync(struct hwc_procs* procs, int dpy,int64_t timestamp) {

reinterpret_cast<cb_context *>(procs)->hwc->vsync(dpy,timestamp);

}

上面这个函数中,procs即前面的&mCBContext.procs,从指针地址上看它和&mCBContext是一致的,因而我们可以强制类型转换为cb_context来进行操作,并由此访问到hwc中的vsync实现:

void HWComposer::vsync(int dpy, int64_t timestamp) {

mEventHandler.onVSyncReceived(dpy, timestamp);

}

HWComposer将VSync信号直接通知给mEventHandler,这个Handler由HWComposer构造时传入,换句话说,我们需要看下是谁创建了HWComposer。

/*frameworks/native/services/surfaceflinger/displayhardware/DisplayHardware.cpp*/

void DisplayHardware::init(uint32_t dpy)

{…

mHwc = newHWComposer(mFlinger, *this, mRefreshPeriod);

从这里可以看出来,HWComposer中的mEventHandler就是DisplayHardware对象,所以后者必须要继承自HWComposer::EventHandler,以此处理产生的onVSyncReceived事件。

(2)软件源

软件源和硬件源的最大区别是它需要启动一个新线程VSyncThread,其运行优先级与SurfaceFlinger的工作线程是一样的,都是-9。从理论的角度讲,任何通过软件定时来实现的机制都不可能是100%可靠的,即使优先级再高也可能出现延迟和意外。不过如果“不可靠”的机率很小,而且就算出现意外时不至于是致命错误,那么还是可以接受的。所以说VSyncThread从实践的角度来讲,的确起到了很好的作用。

bool HWComposer::VSyncThread::threadLoop() {

/*Step1. 系统是否使能了VSync信号发生机制*/

{ // 自动锁控制范围

Mutex::Autolock_l(mLock);

while (!mEnabled) {//VSync信号开关

mCondition.wait(mLock);

}

}

/*Step2. 计算产生VSync信号的时间*/

const nsecs_t period = mRefreshPeriod;//信号的产生间隔

const nsecs_t now =systemTime(CLOCK_MONOTONIC);

nsecs_t next_vsync =mNextFakeVSync;//产生信号的时间

nsecs_t sleep = next_vsync- now; //需要休眠的时长

if (sleep < 0) {//已经过了时间点

sleep = (period - ((now - next_vsync) %period));

next_vsync = now +sleep;

}

mNextFakeVSync =next_vsync + period; //再下一次的VSync时间

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);

if (err == 0) {

mHwc.mEventHandler.onVSyncReceived(0, next_vsync);//和硬件源是一样的回调

}

return true;

}

Step1@ VSyncThread::threadLoop. 关于自动锁的使用我们已经分析过很多次了,不再赘述。这里要注意的是mEnabled这个变量,它是用于控制是否产生VSync信号的一个使能变量。当系统希望关闭VSync信号发生源时,调用VSyncThread::setEnabled(false),否则传入true。假如mEnabled为false时,VSyncThread就处于等待状态,直到有人再次使能这个线程。

Step2@ VSyncThread::threadLoop. 接下来的代码用于真正产生一个VSync信号。可以想象一下,无非就是这些步骤:

·计算下一次产生VSync信号的时间

·进入休眠

·休眠时间到了后,就代表应该发出VSync信号了,通知感兴趣的人

·循环往复

变量mRefreshPeriod指定了产生VSync信号的间隔。它是在DisplayHardware::init中计算出来的:

mRefreshPeriod = nsecs_t(1e9 / mRefreshRate);

如果mRefreshRate为60Hz的话,mRefreshPeriod就差不多是16ms。

因为mNextFakeVSync代表的是“下一次”产生信号的时间点,所以首先将next_vsync=mNextFakeVSync。接着计算sleep,也就是离产生信号的时间点还有多长(同时也是需要休眠的时间)。那么如果sleep的结果小于0呢?代表我们已经错过了这一次产生信号的最佳时间点,这是有可能发生的。在这种情况下,就计算下一次最近的VSync离现在还剩多少时间,公式如下:

sleep = (period - ((now - next_vsync) % period));

我们以下图来表述下采用这个公式的依据:



图 11?33 休眠时间推算简图

这个图的前提是now超时时间不超过一个period。因而公式中还要加上%period。

计算完成sleep后,mNextFakeVSync= next_vsync +period。这是因为mNextFakeVSync代表的是下一次threadLoop需要用到的时间点,而next_vsync是指下一次(最近一次)产生VSync的时间点。

如何在指定的时间点再产生信号呢?有两种方法,其一是采用定时器回调,其二就是采用休眠的形式主动等待,这里使用的是后一种。

可想而知这里的时间要尽可能精准,单位是nanosecond,即纳秒级。函数clock_nanosleep的第一个入参是CLOCK_MONOTONIC,这种时钟更加稳定,且不受系统时间的影响。

当休眠时间到了后,表示产生信号的时刻到了。根据前面的分析,就是通过mEventHandler.onVSyncReceived()回调来通知对消息感兴趣的人,这个做法软硬件都一样。

一次信号产生完成后,函数直接返回true,似乎没有看到循环的地方?这是因为当threadLoop返回值为“真”时,它将被系统再一次调用,从而循环起来。不清楚的可以参阅一下Thread类的实现。

接下来看下DisplayHardware如何处理这个VSync信号的。

中间过程很简单,我们就不一一解释。在DisplayHardware::onVSyncReceived中,它又再次调用内部mVSyncHandler的onVSyncReceived(),将消息向上一层传递。这个变量由EventThread在onFirstRef时通过DisplayHardware::setVSyncHandler()设置,代表的是EventThread对象本身,如下:

void EventThread::onFirstRef() {

mHw.setVSyncHandler(this);//this指针代表EventThread对象

所以VSync信号被进一步递交到了EventThread中。显然,它也不是终点。

void EventThread::onVSyncReceived(int, nsecs_t timestamp) {

Mutex::Autolock _l(mLock);

mVSyncTimestamp =timestamp;

mCondition.broadcast();//有人在等待事件的到来

}

等待VSync事件的地方很多,其中最重要的是EventThread::threadLoop(),这个函数将负责对VSync进行分发,决定谁有权利来最终处理这一事件。

这个函数的主体逻辑还是比较简单的,不过因为很长,内部又夹杂着多个循环体,显得不好理解,因此我们只摘选最重要的一部分来加快大家的阅读。

bool EventThread::threadLoop() {

nsecs_t timestamp;

DisplayEventReceiver::Event vsync;

Vector<wp<EventThread::Connection> > displayEventConnections;

do {//Step1. 第一个循环体

Mutex::Autolock_l(mLock);

do {…//Step2. 第二个循环体,决定是否上报VSync

} while(true);

//跳出循环,接下来就要准备分发VSync了

mDeliveredEvents++;

mLastVSyncTimestamp =timestamp;

const size_t count =mDisplayEventConnections.size();

for (size_t i=0 ;i<count ; i++) {

…//Step3. 第三个循环中逐个判断各connection是否需要上报

if (reportVsync) {

displayEventConnections.add(connection);

}

}

} while(!displayEventConnections.size());//只要size不等于0就可以退出循环了

// 终于开始分发了。。。

vsync.header.type =DisplayEventReceiver::DISPLAY_EVENT_VSYNC;

vsync.header.timestamp =timestamp;

vsync.vsync.count =mDeliveredEvents;

const size_t count =displayEventConnections.size();

for (size_t i=0 ;i<count ; i++) {//Step4. 第四个循环体,分发事件

sp<Connection>conn(displayEventConnections[i].promote());

if (conn != NULL) {

status_t err =conn->postEvent(vsync);//通知connection发起者

if (err == -EAGAIN|| err == -EWOULDBLOCK) {

//这两个错误是指对方当前不接受事件,有可能是暂时性的

} else if (err< 0) {

//发生了致命错误,一律移除

removeDisplayEventConnection(displayEventConnections[i]);

}

} else {//connection已经死了,将它移除

removeDisplayEventConnection(displayEventConnections[i]);

}

}



return true;

}

一共有四个循环体,看起来很乱,我们先以伪代码的形式来重新表述一遍:

do {//第一个循环体

do {

//第二个循环体,判断当前系统是否允许上报VSync

} while(true);

for (size_t i=0 ; i<count ; i++) {

//第三个循环体,逐个计算需要上报的connection个数

}

} while (!displayEventConnections.size());/*一旦需要上报的连接数超过0,

就可以退出循环了*/

for (size_t i=0 ; i<count ; i++) {

/*第四个循环,开始实际的分发。这时要先考虑connection是否死亡,然后就是判断分发后是否有异常返回,比如EWOULDBLOCK等等。对于暂态的错误,理论上是要再重发的,不过当前系统还没有这么做。的确,一方面这将使程序逻辑变得复杂,另一方面,即便丢一两个VSYNC,也无伤大局。所以从源代码注释来看,将来这部分也不会改善。*/

}

相信大家结合这段伪代码再来对照源码,就比较清楚了。

对VSYNC信号感兴趣的人,可以通过registerDisplayEventConnection()来与EventThread建立一个连接。搜索代码可以发现,当前系统中建立了连接的对象是MessageQueue,具体代码在MessageQueue::setEventThread()中。

我们以下图来总结本小节的内容:



图 11?34 VSYNC信号的产生与分发

整体逻辑关系相对复杂,建议大家在做源码分析时,以下面两条线索进行:

l VSync信号的传递流向

l 各个类的静态依赖关系。比如DisplayHardware持有一个HWComposer对象,同时这个对象的mEventHandler成员变量又指向DisplayHardware

英雄会第四届在线编程大赛·线上初赛:带通配符的数2014开源技术大会(读书汇)CSDN博客“我的IT成长路”活动 OpenStack企业应用之路浅析

GUI系统之SurfaceFlinger(12)VSync信号的产生和处理

分类: Android专栏 2013-05-21 13:51 2741人阅读 评论(2) 收藏 举报

目录(?)[+]

文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。

转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/

GUI系统之SurfaceFlinger章节目录:

blog.csdn.net/uiop78uiop78/article/details/8954508

1.1 VSync的产生和处理

前面小节ProjectButter中我们学习了Android 4.1显示系统中的新特性,其中一个就是加入了VSync同步。我们从理论的角度分析了采用这一机制的必要性和运作机理,那么SurfaceFlinger具体是如何实施的呢?

先来想一下有哪些东西要考虑:

·VSync信号的产生和分发

如果有硬件主动发出这一信号,那是最好的了;否则就得通过软件定时模拟来产生

·VSync信号的处理

当信号产生后,SurfaceFlinger如何在最短的时间内响应,具体处理流程是怎么样子的

1.1.1 VSync信号的产生和分发

在Android源码surfaceflinger目录下有一个displayhardware文件夹,其中HWComposer的主要职责之一,就是用于产生VSync信号。

/*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)

{

charvalue[PROPERTY_VALUE_MAX];

property_get("debug.sf.no_hw_vsync", value, "0"); //系统属性

mDebugForceFakeVSync =atoi(value);

bool needVSyncThread =false;//是否需要软件模拟VSync

int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);//加载HAL模块

if (err == 0) {

err = hwc_open(mModule, &mHwc);//打开module

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) {//用于调试

mHwc->methods->eventControl(mHwc, HWC_EVENT_VSYNC, 0);

}

} else {//有可能支持VSync的硬件模块是这个版本以后才加入的,老版本仍然需要软件模拟

needVSyncThread = true;

}

}

} else {

needVSyncThread =true; //硬件模块打开失败,只能用软件模拟

}

if (needVSyncThread) {

mVSyncThread = new VSyncThread(*this);//创建一个产生VSync信号的线程

}

}

这个函数的核心就是决定VSync的“信号发生源”——硬件或者软件模拟。

假如当前系统可以成功加载HWC_HARDWARE_MODULE_ID=“hwcomposer”,并且通过这个库模块能顺利打开设备(hwc_composer_device_t),其版本号又大于HWC_DEVICE_API_VERSION_0_3的话,我们就采用“硬件源”(此时needVSyncThread为false),否则需要创建一个新的VSync线程来模拟产生信号。

(1)硬件源

如果mHwc->registerProcs不为空的话,我们注册硬件回调mCBContext.procs。定义如下:

struct cb_context{

callbacksprocs;

HWComposer*hwc;

};

调用registerProcs()时,传入的参数是&mCBContext.procs。后期当有事件产生时,比如vsync或者invalidate,硬件模块将分别通过procs.vsync和procs.invalidate来通知HWComposer。

void HWComposer::hook_vsync(struct hwc_procs* procs, int dpy,int64_t timestamp) {

reinterpret_cast<cb_context *>(procs)->hwc->vsync(dpy,timestamp);

}

上面这个函数中,procs即前面的&mCBContext.procs,从指针地址上看它和&mCBContext是一致的,因而我们可以强制类型转换为cb_context来进行操作,并由此访问到hwc中的vsync实现:

void HWComposer::vsync(int dpy, int64_t timestamp) {

mEventHandler.onVSyncReceived(dpy, timestamp);

}

HWComposer将VSync信号直接通知给mEventHandler,这个Handler由HWComposer构造时传入,换句话说,我们需要看下是谁创建了HWComposer。

/*frameworks/native/services/surfaceflinger/displayhardware/DisplayHardware.cpp*/

void DisplayHardware::init(uint32_t dpy)

{…

mHwc = newHWComposer(mFlinger, *this, mRefreshPeriod);

从这里可以看出来,HWComposer中的mEventHandler就是DisplayHardware对象,所以后者必须要继承自HWComposer::EventHandler,以此处理产生的onVSyncReceived事件。

(2)软件源

软件源和硬件源的最大区别是它需要启动一个新线程VSyncThread,其运行优先级与SurfaceFlinger的工作线程是一样的,都是-9。从理论的角度讲,任何通过软件定时来实现的机制都不可能是100%可靠的,即使优先级再高也可能出现延迟和意外。不过如果“不可靠”的机率很小,而且就算出现意外时不至于是致命错误,那么还是可以接受的。所以说VSyncThread从实践的角度来讲,的确起到了很好的作用。

bool HWComposer::VSyncThread::threadLoop() {

/*Step1. 系统是否使能了VSync信号发生机制*/

{ // 自动锁控制范围

Mutex::Autolock_l(mLock);

while (!mEnabled) {//VSync信号开关

mCondition.wait(mLock);

}

}

/*Step2. 计算产生VSync信号的时间*/

const nsecs_t period = mRefreshPeriod;//信号的产生间隔

const nsecs_t now =systemTime(CLOCK_MONOTONIC);

nsecs_t next_vsync =mNextFakeVSync;//产生信号的时间

nsecs_t sleep = next_vsync- now; //需要休眠的时长

if (sleep < 0) {//已经过了时间点

sleep = (period - ((now - next_vsync) %period));

next_vsync = now +sleep;

}

mNextFakeVSync =next_vsync + period; //再下一次的VSync时间

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);

if (err == 0) {

mHwc.mEventHandler.onVSyncReceived(0, next_vsync);//和硬件源是一样的回调

}

return true;

}

Step1@ VSyncThread::threadLoop. 关于自动锁的使用我们已经分析过很多次了,不再赘述。这里要注意的是mEnabled这个变量,它是用于控制是否产生VSync信号的一个使能变量。当系统希望关闭VSync信号发生源时,调用VSyncThread::setEnabled(false),否则传入true。假如mEnabled为false时,VSyncThread就处于等待状态,直到有人再次使能这个线程。

Step2@ VSyncThread::threadLoop. 接下来的代码用于真正产生一个VSync信号。可以想象一下,无非就是这些步骤:

·计算下一次产生VSync信号的时间

·进入休眠

·休眠时间到了后,就代表应该发出VSync信号了,通知感兴趣的人

·循环往复

变量mRefreshPeriod指定了产生VSync信号的间隔。它是在DisplayHardware::init中计算出来的:

mRefreshPeriod = nsecs_t(1e9 / mRefreshRate);

如果mRefreshRate为60Hz的话,mRefreshPeriod就差不多是16ms。

因为mNextFakeVSync代表的是“下一次”产生信号的时间点,所以首先将next_vsync=mNextFakeVSync。接着计算sleep,也就是离产生信号的时间点还有多长(同时也是需要休眠的时间)。那么如果sleep的结果小于0呢?代表我们已经错过了这一次产生信号的最佳时间点,这是有可能发生的。在这种情况下,就计算下一次最近的VSync离现在还剩多少时间,公式如下:

sleep = (period - ((now - next_vsync) % period));

我们以下图来表述下采用这个公式的依据:



图 11?33 休眠时间推算简图

这个图的前提是now超时时间不超过一个period。因而公式中还要加上%period。

计算完成sleep后,mNextFakeVSync= next_vsync +period。这是因为mNextFakeVSync代表的是下一次threadLoop需要用到的时间点,而next_vsync是指下一次(最近一次)产生VSync的时间点。

如何在指定的时间点再产生信号呢?有两种方法,其一是采用定时器回调,其二就是采用休眠的形式主动等待,这里使用的是后一种。

可想而知这里的时间要尽可能精准,单位是nanosecond,即纳秒级。函数clock_nanosleep的第一个入参是CLOCK_MONOTONIC,这种时钟更加稳定,且不受系统时间的影响。

当休眠时间到了后,表示产生信号的时刻到了。根据前面的分析,就是通过mEventHandler.onVSyncReceived()回调来通知对消息感兴趣的人,这个做法软硬件都一样。

一次信号产生完成后,函数直接返回true,似乎没有看到循环的地方?这是因为当threadLoop返回值为“真”时,它将被系统再一次调用,从而循环起来。不清楚的可以参阅一下Thread类的实现。

接下来看下DisplayHardware如何处理这个VSync信号的。

中间过程很简单,我们就不一一解释。在DisplayHardware::onVSyncReceived中,它又再次调用内部mVSyncHandler的onVSyncReceived(),将消息向上一层传递。这个变量由EventThread在onFirstRef时通过DisplayHardware::setVSyncHandler()设置,代表的是EventThread对象本身,如下:

void EventThread::onFirstRef() {

mHw.setVSyncHandler(this);//this指针代表EventThread对象

所以VSync信号被进一步递交到了EventThread中。显然,它也不是终点。

void EventThread::onVSyncReceived(int, nsecs_t timestamp) {

Mutex::Autolock _l(mLock);

mVSyncTimestamp =timestamp;

mCondition.broadcast();//有人在等待事件的到来

}

等待VSync事件的地方很多,其中最重要的是EventThread::threadLoop(),这个函数将负责对VSync进行分发,决定谁有权利来最终处理这一事件。

这个函数的主体逻辑还是比较简单的,不过因为很长,内部又夹杂着多个循环体,显得不好理解,因此我们只摘选最重要的一部分来加快大家的阅读。

bool EventThread::threadLoop() {

nsecs_t timestamp;

DisplayEventReceiver::Event vsync;

Vector<wp<EventThread::Connection> > displayEventConnections;

do {//Step1. 第一个循环体

Mutex::Autolock_l(mLock);

do {…//Step2. 第二个循环体,决定是否上报VSync

} while(true);

//跳出循环,接下来就要准备分发VSync了

mDeliveredEvents++;

mLastVSyncTimestamp =timestamp;

const size_t count =mDisplayEventConnections.size();

for (size_t i=0 ;i<count ; i++) {

…//Step3. 第三个循环中逐个判断各connection是否需要上报

if (reportVsync) {

displayEventConnections.add(connection);

}

}

} while(!displayEventConnections.size());//只要size不等于0就可以退出循环了

// 终于开始分发了。。。

vsync.header.type =DisplayEventReceiver::DISPLAY_EVENT_VSYNC;

vsync.header.timestamp =timestamp;

vsync.vsync.count =mDeliveredEvents;

const size_t count =displayEventConnections.size();

for (size_t i=0 ;i<count ; i++) {//Step4. 第四个循环体,分发事件

sp<Connection>conn(displayEventConnections[i].promote());

if (conn != NULL) {

status_t err =conn->postEvent(vsync);//通知connection发起者

if (err == -EAGAIN|| err == -EWOULDBLOCK) {

//这两个错误是指对方当前不接受事件,有可能是暂时性的

} else if (err< 0) {

//发生了致命错误,一律移除

removeDisplayEventConnection(displayEventConnections[i]);

}

} else {//connection已经死了,将它移除

removeDisplayEventConnection(displayEventConnections[i]);

}

}



return true;

}

一共有四个循环体,看起来很乱,我们先以伪代码的形式来重新表述一遍:

do {//第一个循环体

do {

//第二个循环体,判断当前系统是否允许上报VSync

} while(true);

for (size_t i=0 ; i<count ; i++) {

//第三个循环体,逐个计算需要上报的connection个数

}

} while (!displayEventConnections.size());/*一旦需要上报的连接数超过0,

就可以退出循环了*/

for (size_t i=0 ; i<count ; i++) {

/*第四个循环,开始实际的分发。这时要先考虑connection是否死亡,然后就是判断分发后是否有异常返回,比如EWOULDBLOCK等等。对于暂态的错误,理论上是要再重发的,不过当前系统还没有这么做。的确,一方面这将使程序逻辑变得复杂,另一方面,即便丢一两个VSYNC,也无伤大局。所以从源代码注释来看,将来这部分也不会改善。*/

}

相信大家结合这段伪代码再来对照源码,就比较清楚了。

对VSYNC信号感兴趣的人,可以通过registerDisplayEventConnection()来与EventThread建立一个连接。搜索代码可以发现,当前系统中建立了连接的对象是MessageQueue,具体代码在MessageQueue::setEventThread()中。

我们以下图来总结本小节的内容:



图 11?34 VSYNC信号的产生与分发

整体逻辑关系相对复杂,建议大家在做源码分析时,以下面两条线索进行:

l VSync信号的传递流向

l 各个类的静态依赖关系。比如DisplayHardware持有一个HWComposer对象,同时这个对象的mEventHandler成员变量又指向DisplayHardware

二 : 如何理解信号与系统 数字信号处理 通信原理三者的相


网友匿名用户[数字信号处理系统]如何理解信号与系统 数字信号处理 通信原理三者的相互联系?给出的答复:
建议首先对专业教材目录进行对比,了解有哪些内容相关联,还有就是一定要认真阅读教材的序言(引言),其中都有作者对该科目与相关交叉科目关系的叙述。包括每章后的总结,多少也会有类似的叙述。

综上,你完全可以自己总结的。放在其他专业也是同样道理。
(似乎有些答非所问,但我始终觉得“授人以渔”好过“授人以鱼”。)


网友郭大山[数字信号处理系统]如何理解信号与系统 数字信号处理 通信原理三者的相互联系?给出的答复:
信号与系统是基础,主要是连续信号理论分析;实际应用数字电路处理离散信号,因而需要数字信号处理,不得不说FFT是个里程碑的突破;分析信号方法有了,然后组成个通信系统,从发射端经信道到接收端,整个系统分析叫通信原理


网友呵呵[数字信号处理系统]如何理解信号与系统 数字信号处理 通信原理三者的相互联系?给出的答复:
我从课程学习的角度来答。
信号与系统涵盖了信号分析和实际系统分析,其中所涉及的基本概念,基本分析方法适用于很多的实际使用场景。在本科学习的时候,大多以分析确定性信号经过线性时不变系统的的各种性能,分析方法最重要的还是拉普拉斯那一套。
在信号与系统的分析当中,有基本的分支:连续系统和离散系统。数字信号处理属于离散系统分析,数字信号处理就是学习数字信号(离散信号经过时间离散成为数字信号)的表示,以及经过系统的信号表达分析,用的最多的就是离散的z变换,工具则多是讲FFT,实际处理当中方法还有很多。
通信原理则更为具体,研究一个相对具体的场景,这个场景下的信号与通信系统有其自身的特点。通信信号的产生,传输以及解调等等用到的基本方法都是信号与系统当中的,通信的发展由模拟信号到数字信号,信号表达的改变方法相应的调整。


网友蒙面大侠[数字信号处理系统]如何理解信号与系统 数字信号处理 通信原理三者的相互联系?给出的答复:
想了一会儿觉得好像怎么说都不够完整。我觉得信号与系统更多的是基于局部的物理现象,给一个激励得到怎样的响应,核心是利用时频域中更简单的一个来分析信号;DSP则是如何利用计算机处理信号,核心是离散傅里叶变换;而通信原理则更着眼于系统(此系统非彼系统),信道是核心,一切的调制编码抗衰落等都是围绕信道来进行的。

三 : 数字信号处理系统的基本原理及特点(要详细一点的介绍)

数字信号处理系统的基本原理及特点(要详细一点的介绍)

数字信号处理系统的基本原理及特点(要详细一点的介绍)的参考答案

谁说百度学术方面不行?这本身是个伪命题.不是百度行不行,是百度上的人行不行.据我所知,牛人还是很多的.

回答楼主的疑问.

数字信号处理是将信号以数字方式表示并处理的理论和技术.数字信号处理与模拟信号处理是信号处理的子集. 数字信号处理系统的优点:体积小、功耗低、精度高、可靠性高、灵活性大、易于大规模集成、可进行二维与多维处理.

随着大规模集成电路以及数字计算机的飞速发展,加之从60年代末以来数字信号处理理论和技术的成熟和完善,用数字方法来处理信号,即数字信号处理,已逐渐取代模拟信号处理. 随着信息时代、数字世界的到来,数字信号处理已成为一门极其重要的学科和技术领域.

数字信号处理的目的是对真实世界的连续模拟信号进行测量或滤波.因此在进行数字信号处理之前需要将信号从模拟域转换到数字域,这通常通过模数转换器实现.而数字信号处理的输出经常也要变换到模拟域,这是通过数模转换器实现的.

数字信号处理的算法需要利用计算机或专用处理设备如数字信号处理器(DSP)和专用集成电路(ASIC)等.数字信号处理技术及设备具有灵活、精确、抗干扰强、设备尺寸小、造价低、速度快等突出优点,这些都是模拟信号处理技术与设备所无法比拟的.

数字信号处理的核心算法是离散傅立叶变换(DFT),是DFT使信号在数字域和频域都实现了离散化,从而可以用通用计算机处理离散信号.而使数字信号处理从理论走向实用的是快速傅立叶变换(FFT),FFT的出现大大减少了DFT的运算量,使实时的数字信号处理成为可能、极大促进了该学科的发展.

希望对你有用~

本文标题:数字信号处理系统-GUI系统之SurfaceFlinger(12)VSync信号的产生和处理
本文地址: http://www.61k.com/1092032.html

61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1