vsync信号
Posted Achillisjack
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vsync信号相关的知识,希望对你有一定的参考价值。
上个小节说明了HWC模块的加载等操作,并且也说明了HWC模块主要用于产生vsync信号,现在的问题是, vsync信号是如何产生的呢? 又是如何传输到SurfaceFlinger 中,处理的呢?在上面的论述中,HWComposer 的构造方法在加载完FB模块打开设备文件以及加载HWC模块之后,会注册vsync信号,
mHwc->registerProcs(mHwc, &mCBContext->procs);
HWComposer_hwc1.h中的mCBContext变量申明如下,
cb_context* mCBContext;
是cb_context 的结构体,该结构体定义如下,
HWComposer_hwc1.cpp中的cb_context结构体定义如下,
struct HWComposer::cb_context
struct callbacks : public hwc_procs_t
// these are here to facilitate the transition when adding
// new callbacks (an implementation can check for NULL before
// calling a new callback).
void (*zero[4])(void);
;
callbacks procs;
HWComposer* hwc;
;
里面有2个变量,一个指向HWComposer对象,1个结构体callbacks,这个结构体会传给HAL层的HWC模块,这样,当有vsync信号时,就可以通过这个结构体进行回调。callbacks由继承自 hwc_procs_t, hwcomposer.h中的 hwc_procs_t的定义如下,
typedef struct hwc_procs
void (*invalidate)(const struct hwc_procs* procs);
void (*vsync)(const struct hwc_procs* procs, int disp, int64_t timestamp);
void (*hotplug)(const struct hwc_procs* procs, int disp, int connected);
hwc_procs_t;
invalidate方法:会触发屏幕刷新,在invalidate被调用不久会调用prepare和set,但是不保证调用了invalidate屏幕就一定会刷新,比如之前屏幕已经刷新过了,就不会在刷新。
vsync方法:是分析这部分代码的目的,在收到一个vsync事件,并且HWC_EVENT_VSYNC是enabled的,这个vsync方法会被hwcomposer hal模块调用,其中的参数disp标示这个vsync事件是属于那个显示设备。
hotplug方法:在一个显示设备连接或断开时会调用hotplug,主显示设备一直都是连接的,这个方法不会被调用,主要是针对可热插拔的设备。
对应的HWC的hwc_registerProcs方法逻辑如下,
hwc_context_t* ctx = (hwc_context_t*)(dev);
•••
ctx->proc = procs; //vsync回调HWComposer的vsync函数。
// Now that we have the functions needed, kick off
// the uevent & vsync threads
init_uevent_thread(ctx);
init_vsync_thread(ctx);
也就是说,当HWC模块调用proc中的方法时,实际上是回调hwc_procs 结构体(mCBContext)中对应的方法。当有回调函数注册时,会开启uevent,vsync两个线程。uevent线程跟屏幕invalidate有关, vsync和vsync信号相关,主要分析vsync线程。HWC模块的hwc_vsync.cpp的init_vsync_thread方法调用流程图如下,
init_vsync_thread方法如下,
int ret;
pthread_t vsync_thread;
ALOGI("Initializing VSYNC Thread");
ret = pthread_create(&vsync_thread, NULL, vsync_loop, (void*) ctx);
创建vsync线程,入口方法为vsync_loop。该方法逻辑如下,
1,当不是模拟vsync的情况,当有多个显示设备时,对每个显示设备都要执行回调,发出通知,
do
int err = poll(*pfd, (int)(num_displays * num_events), -1);
•••
在该线程运行过程中通过ioctl系统调用进入到fb驱动等待VSync中断,如果VSync中断到来,则ioctl函数从驱动中返回。
2,使用模拟vsync的情况,通常是明确通过属性设置了或在开机时vsync时间戳节点还没打开,这时候会使用模拟vsync,模拟vsync指发给主显示设备。
do
usleep(16666);
uint64_t timestamp = systemTime();
ctx->proc->vsync(ctx->proc, HWC_DISPLAY_PRIMARY, timestamp);
while (true);
vsync信号间隔16.66ms发送一次,也就是说1秒钟发送60次vsync信号。
回调mCBContext中的vsync方法,在HWComposer_hwc1.cpp中的HWComposer构造方法中,
mCBContext->hwc = this;
mCBContext->procs.invalidate = &hook_invalidate;
mCBContext->procs.vsync = &hook_vsync;
mCBContext中的vsync方法 指向的是HWComposer的hook_vsync方法,如下,
cb_context* ctx = reinterpret_cast<cb_context*>(
const_cast<hwc_procs_t*>(procs));
ctx->hwc->vsync(disp, timestamp);
绕了一圈,最后还是调用HWComposer的vsync方法,调用流程图如下,
HWComposer的vsync方法如下,
char tag[16];
snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
mEventHandler.onVSyncReceived(this, disp, timestamp);
mEventHandler是什么对象呢? 在SurfaceFlinger_hwc1.cpp 的SurfaceFlinger的init方法构造HWComposer对象时,
mHwc.reset(new HWComposer(this,
*static_cast<HWComposer::EventHandler *>(this)));
mHwc->registerCallback(this, mComposerSequenceId);
传入的是SurfaceFlinger对象,因此mEventHandler 是SurfaceFlinger对象。
HWComposer直接通过mEventHandler把vsync信号传到surfaceflinger。onVSyncReceived方法如下,
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);
逻辑很简单,首先调用DispSync的addResyncSample方法判断是否需要Vsync信号,如果需要就调用enableHardwareVsync方法进行处理,否则调用disableHardwareVsync方法进行处理。
以上是关于vsync信号的主要内容,如果未能解决你的问题,请参考以下文章