Vsync从HWC到APP的传递过程

主要可以分成两个阶段:从HWC到SurfaceFlinger和从SurfaceFlinger到APP。

1.从HWC到SurfaceFlinger


Android系统中VSYNC信号分为两种,一种是硬件生成的信号,一种是软件模拟的信号。
硬件信号是由HardwareComposer提供的,HWC封装了相关的HAL层,如果硬件厂商提供的HAL层实现能定时产生VSYNC中断,则直接使用硬件的VSYNC中断,否则HardwareComposer内部会通过VSyncThread来模拟产生VSYNC中断(其实现很简单,就是sleep固定时间,然后唤醒)

无论是硬件Vsync还是软件模拟Vsync,当HWC发出Vsync时,总会被SurfaceFlinger的onVsyncReceived函数拿到。

SurfaceFlinger在init时,会创建两个DispSyncSource,一个用来APP绘制,另一个用来SurfaceFlinger自己合成显示;这两个DispSyncSource对应SurfaceFlinger的两个EventThread线程。

1.1surfaceflinger有4个线程与VSYNC有关。


1个EventControlThread,用于开始/关闭 HWComposer HAL的VSYNC。
1个是DispSyncThread,用于接收HWComposer HAL的VSYNC信号,并分发给EventThread。
2个EventThread。EventThread类主要是接收DispSyncThread发来的VSYNC,并分发给真正使用的人。
这些线程是在surfaceflinger初始化的时候创建的,它们之间的关系如下:

Vsync从HWC到APP的传递过程_第1张图片

1.2 SurfaceFlinger接收和处理Vsync

在讲到SF接收Vsync细节前,需要说下在SF init过程中,在创建两个EventThread时,它对其中自己用的EventThread,即sfEventThread做了一些工作:

void MessageQueue::setEventThread(const sp& eventThread)
{
    mEventThread = eventThread;
    mEvents = eventThread->createEventConnection();
    mEventTube = mEvents->getDataChannel();
    mLooper->addFd(mEventTube->getFd(),0, Looper::EVENT_INPUT,
    MessageQueue::cb_eventReceiver, this);
}

SF自己创建了一个Connection类,这个类就是传递Vsync信息的媒介。其实就注册了一个事件的监听者,得到了发送VSYNC事件通知的BitTube,然后监控这个BitTube中的套接字,并且指定了收到通知后的回调函数。

SurfaceFlinger接收处理Vsync的过程大致为:HWComposer HAL通过callback函数,把VSYNC信号传给DispSyncThread,DispSyncThread传给EventThread。

Vsync从HWC到APP的传递过程_第2张图片

在上面的flow中,SurfaceFlinger通过onVsyncReceived拿到HWC Vsync之后,会利用DiscSync::addResyncSample函数判断是否还需要HWC Vsync作为输入,不需要的话就会使用EventControlThread关掉HWC Vsync。

DiscSync::addResyncSample就是对Vsync的处理过程的开始,具体的过程是在DiscSync::updateModelLocked里面实现。因此DiscSync这个类的作用就是SF用来处理Vsync的。

这里引用http://echuang54.blogspot.tw/2015/01/dispsync.html对它的描述:

我們可以用下圖來了解DispSync的架構, DispSync像是一個PLL, 它的input是硬體VSYNC的時間, 它的feedback是Present Fence的時間, 它的輸出就是SW_VSYNC, SW_VSYNC再根據SF與APP的phase offset做調整, 分別輸出VSYNC-sf與VSYNC-app.


我对DiscSync的总结如下:

(1). app和SurfaceFlinger真正使用的vsync属于sw vsync,这两个vsync是根据HWC vsync推算出来,这两者有一定相位偏移,原因应该是防止app和SurfaceFlinger同时被唤醒进行绘制和显示,造成争夺CPU,这叫做Vsync虚拟化。app 的vsync会先得到响应。

(2). 由于有CPU延时响应可能造成sw vsync超出某个阈值,导致需要HWC vsync校正,此时才会再次打开HWC Vsync。

后面的flow就是SurfaceFlinger调用DispSync的updateModel函数,唤醒DispSyncThread。DispSyncThread通过fireCallbackInvocations函数,告诉DispSyncSource有VSYNC了。

DispSyncSource作为DispSyncThread与EventThread的桥梁,会唤醒EventThread存下vsync。EventThread的threadLoop唤醒后,通过postEvent,向所有注册过的connection发送VSYNC消息。

2 .从SurfaceFlilnger到APP


每个app创建时都会new一个RenderThread,用于管理UI的画图。如同上面讲的4个线程, 这个RenderThread也是继承Thread类,当我们调用它的成员函数run的时候,就会创建一个新的线程。这个新的线程的入口点函数为RenderThread类的成员函数threadLoop。

RenderThread类有一个成员变量mQueue,描述的是一个Task Queue。这个Queue用于保存所有需要执行的Task,每一个Task都是用一个RenderTask对象来描述。同时,RenderTask类有一个成员变量mRunAt,用来表明Task的执行时间。这样,保存在Task Queue的Task就可以按照执行时间从先到后的顺序排序,这个mRunAt最终会存VSYNC。于是,RenderThread类的成员函数nextTask通过判断排在队列头的Task的执行时间是否小于等于当前时间,就可以知道当前是否有Task需要执行。如果有Task需要执行的话,就将它返回给调用者。我们可以把Task当做是画图任务。

RenderThread初始化的时候,会new DisplayEventReceiver。

DisplayEventReceiver就是APP接收Vsync的接口。DisplayEventReceiver在构造函数里会调用surfaceflinger去注册一个connection;APP与SurfaceFlingger是两个进程,这里DisplayEventReceiver调用surfaceflinger注册Connection的过程是一个远程调用,由Binder实现。Connection类是Binder服务端的实现,继承了BnDisplayEventConnection;在APP里面的Binder引用对象实现了IDisplayEventConnection接口。

Connection类里面有一个重要的成员mChannel,它是BitTube类。BitTube是啥? 字面意思就是字节管道。如果看它的构造函数,就能发现,其实它就是包了socket,用于进程间通信。

DisplayEventReceiver构造函数,就首先会调用surfaceflinger去注册一个connection,connection又会创建BitTube。客户端便可以通过getDataChannel()获得这个BitTube。
那么进程通信就可以开始了。
surfaceflinger进程的EventThread把VSYNC不断的往BitTube写(想象成往socket写),而app进程将会创建DisplayEventReceiver,该app进程又可以不断的读BitTube(想象成读socket)。这样,VSYNC就可以传输了。

Vsync从HWC到APP的传递过程_第3张图片


Reference


http://blog.csdn.net/newchenxf/article/details/49131167

http://blog.csdn.net/michaelcao1980/article/details/43233765

http://echuang54.blogspot.tw/2015/01/dispsync.html

你可能感兴趣的:(Android,frameworks)