
近期关于event[0]的讨论热度持续攀升,我们通过多方渠道收集整理了相关资讯,并进行了系统化的梳理。若这些内容恰好能为您提供参考,将是我们最大的荣幸。
EVENT是表示当一个事件发生了,但是VHDL里面要求必须说明到底发生了什么事,VHDL才能根据发生的事情 来做判断!你只给出了一个EVENT VHDL不知道是发生什么事情,所以它不能判断!!! 换句通俗的话说,VHDL不支持无知的发生事件!
时钟变化有包括上升和下降,还有没变,if clk'event and clk='1' 表示上升
同样的 clk'event and clk='0'表示下降 再加个else 就表示没变化了
Vsync(垂直同步信号量),用来同步渲染,让AppUI和SurfaceFlinger可以按硬件产生的VSync节奏进行工作。
Vsync要解决的问题:
为什么会产生这样的问题?
CPU负责对UI进行更新,GPU负责对UI进行渲染,两者的频率不一致,会导致CPU还未更新完成,就被GPU渲染到了屏幕上。所以会出现上的问题。
如何解决这个问题?
解决这个问题的方法就是让CPU和GPU以相同的节奏进行工作。如下图所示
让CPU和GPU以相同的频率进行工作,这就是Vsync要做的工作。Vsync以固定的频率发出信号,每当收到CPU先对UI进行更新,然后GPU再进行绘制,这样就可以解决上面的问题了。
那Android的Vsync机制是如何进行的呢?
这张图可以很明显的看出Vsync事件的传递过程。
Vsync信号并不是有硬件直接产生,而是由DispSync线程产生的。DispSync会根据HWC产生的VSync进行采样,创建模型,然后输出了SW_VSYNC信号,SW_VSYNC再根据SF和APP的phase offset做调整,分别输出给Vsync-sf和Vsync-app。
再看下几个类之间的关系图
在分析HWComposer的时候,HWComposer中会注册硬件Vsync事件回调,在硬件Vsync事件到来的时候,回调HWComposer的vsync函数。
HWComposer接收到硬件的Vsync事件并没有直接传递给系统使用,而是通过SurfaceFlinger将Vsync事件,添加到了DispSync的Vsync事件样本,当DispSync采样完成后,则会停止硬件Vsync事件,由软件Vsync根据样本的计算结果产生Vsync事件。
mPrimaryHWVsyncEnabled变量控制DispSync是否需要采集样本,当模型Vsync周期有误差时需要重新打开硬件Vsync,再次采集硬件Vsync样本。
addResyncSample方法主要作用是添加采样样本到Buffer中,DispSync中维护了一个环形的Buffer,大小为32个,每当有新样本过来时候,则将样本添加到Buffer中,如果Buffer已经满了,则替换掉最老的样本。
样本更新后调用updateModelLocked来计算更新DispSync模型。
计算平均周期模型和平均偏差模型。
如何计算平均周期?
将所有样本的间隔时间相加,然后除以间隔数,求出平均间隔时间.
如何计算平均偏差?
如果完全准时的样本,应该可以整除平均,余数为0,有偏差的则余数不为0,所以对所有的样本除以mPeriod平均周期时间,计算余数,将余数又转换成弧度. 计算X和Y, 求X和Y的平均值,然后再由平均X,Y求出弧度,再转换成偏差值。这样就计算出平均偏差了.
调用VsyncThread的mCond.signal()通知VsyncThread模型更新完成。
SurfaceFlinger的Vsync并不是直接使用硬件产生Vsync,而是由软件根据硬件Vsync创建了一个数据模型来模拟产生Vsync信号。负责产生软件Vsync信号的就是DispSync。
DispSync是SurfaceFlinger中的一个变量。
mPrimaryDispSync就是Vsync的信号源,我们先看下Vsync信号是如何产生的?
DispSync对象在创建的时候会启动一个VsyncThread线程,该线程用于模拟Vsync信号。然后我们看下VsyncThread线程的threadloop方法
VsyncThread刚开始由于mPeriod=0,也就是说当前线程还不知道按照什么样的频率产生Vsync信号,所以会等待mPeriod周期模型的更新。
什么时候设置更新mPeriod的时间呢?
就是上面提到的,应用模型样本计算完成后会设置mPeriod和mPhase,这样VsyncThread就会继续执行
当有Vsync的周期时间和偏差时间后,VsyncThread就可以模拟产生软件Vsync信号了。产生Vsync信号就会通过回调接口通知监听者.
DispVsync有两个监听者,就是我们上面提到的SurfaceFlinger和APP,SurfaceFlinger和App所需要的Vsync时间不是完全一致。App一般先接到Vsync信号,还是绘制UI,然后SurfaceFlinger再接收到Vsync信号完成UI合成。
VsyncThread做了什么事情呢?
首先计算下次Vsync产生的时间,计算下次产生时间会根据两个监听者上次接收到Vsync时间,然后加上周期时间,偏差时间,和APP或者SF自己的偏差时间。得到下次Vsync时间。
得到最近的下次执行时间,Vsync只要Wait相应的时间差就可了,等到执行时间后回调SF或者APP的Vsync信号。这样Vsync信号就产生了.
上面讲DispSync提到,DispSync有两个监听者,这两个监听这就是两个DisplaySyncSource对象。两个对象是在SurfaceFlinger的init进程创建的.
init中创建了两个DispSyncSource对象, 一个是SF的sfVsyncSrc,一个是SurfaceFlinger的sfVsyncSrc对象. DiplaySyncSource构造方法中会保存一个syncOffet值,表示自己收到Vsync偏差时间.
DispSync计算Vsync产生时间的时候,会根据这个偏差进行计算.也就是上面公式中的自定义偏差offset。
DispSync有一些重要的函数,具体如下:
这样,我们就大概理解了Vsync信号的产生过程。
1:HWC硬件产生Vsync信号,给DispSync添加样本
2:DispSync根据样本计算Vsync周期,然后产生软件Vsync信号。计算Vsync事件会根据不同的Listenr计算不同的时间.
3:DisplaySyncSource是DispSync的监听者,有两个DisplaySyncSource对象,分别代表SF和APP的DisplaySyncSource,两个回调的Vsync时间不同.
4:DisplaySyncSource收到Vsync事件后,会发给他自己的监听者EventThread
EventThread收到Vsync时间后会存放到mVSyncEvent[0]中,通知EventThread线程进行处理。
为什么要有两个DisplaySyncSource且时间不一样呢?
具体如上图所示
App绘制UI, 绘制完成后交给SurfaceFlinger进行合成, 所以App绘制时间优先于SF合成时间,将两者时间错开,避免资源竞争,增加效率。如何APP和SF的偏差时间设置好的话,APP + SF在一个Vsync周期内就可以绘制合成,在下一个Vsync周期到来的时候就可以显示到屏幕上了。
关于event[0]的探讨就到这里,您是否还有其他想了解的内容?欢迎在评论区留言告诉我们,同时别忘了点击关注哦!