VSync信号系统与SurfaceFlinger


    SurfaceFlinger是Android中的系统服务, 负责Layer合成与VSync信号监听分发。它接收所有Window的Surface作为输入,计算出每个Surface在最终合成图像中的位置,然后交由HWComposer生成最终的显示Buffer, 然后显示到特定的显示设备上。

一.VSync系统的初始化

1.SurfaceFlinger的初始化

    SurfaceFlinger在初始化时会调用init方法。在init方法中主要做了四件事:

1)创建HWComposer,HWComposer是一个HAL组件,为SurfaceFlinger提供服务。

2)将HWComposer保存到CompositionEngine中。

3)为HWComposer设置setCallback回调,使SurfaceFlinger可以接收HAL层回调。

4)获取屏幕设备信息。DisplayDevice是屏幕硬件的抽象,通过DisplayDevice可以获取和设置屏幕的参数。

5)处理内置屏幕相关的初始化。
0

2.VSync信号的初始化

    在SurfaceFlinger的initScheduler方法中会初始化VSync信号。主要做了九件事:

1)获取屏幕刷新率配置。

2)获取帧率配置。

3)获取VSync配置,包含VSync-app偏移量与VSync-appSf偏移量等。

4)创建Schdueler,Schdueler负责SurfaceFlinger中VSync信号的注册与分发。ISchedulerCallback用于SurfaceFlinger监听Schdueler的状态。ICompositor用于Schdueler调用SurfaceFlingerLayer合成相关的功能。

5)初始化Schdueler。

6)开启硬件VSync信号采样,校准软件VSync信号。

7)创建VSync-app信号的分发线程,用于接收App层VSync信号的注册与分发。

8)创建VSync-appSf信号的分发线程。

9)初始化MessageQueue,MessageQueue用于SurfaceFlinger注册监听VSync-appSf信号。
1

2.1 Scheduler的初始化

    在Scheduler创建完成后,会调用Scheduler的registerDisplay方法对Scheduler进行初始化。在registerDisplay方法中主要做了两件事:

1)创建VsyncSchedule,VsyncSchedule是Scheduler功能实现的核心。

2)保存VsyncSchedule,并回调通知外部监听者有新的VsyncSchedule。
2
    在VsyncSchedule的构造方法中,会创建三个重要组件。
3

  • VSyncTracker:实现类为VSyncPredictor,负责接收外部VSync采样,计算软件VSync模型的参数。
  • VsyncController:实现类为VSyncReactor,负责约束管理VSyncTracker的行为,控制VSyncTracker的采样。
  • VSyncDispatch:实现类为VSyncDispatchTimerQueue,负责软件VSync信号的产生和分发。

2.2 ConnectionHandle的创建

    在Scheduler的createEventThread方法中,主要做了三件事:

1)获取VsyncSchedule。

2)根据VsyncSchedule创建EventThread。

3)根据EventThread创建ConnectionHandle。
4
    在Scheduler的createConnection方法中,主要做了三件事:

1)创建ConnectionHandle。

2)调用createConnectionInternal方法,创建EventThreadConnection。EventThreadConnection用于连接EventThread与App层负责注册VSync信号的组件,后续用于通知App层负责注册VSync信号的组件。

3)将EventThreadConnection和EventThread封装成Connection,并保存ConnectionHandle与Connection。
5
    在Scheduler的createConnectionInternal方法中,会将EventThread作为参数,创建EventThreadConnection。
6

2.3 MessageQueue的初始化

    由于Scheduler继承了MessageQueue,因此在调用Scheduler的initVsync方法时,实际调用的是MessageQueue的initVsync方法。initVsync方法又调用了onNewVsyncScheduleLocked方法。
7
    在MessageQueue的onNewVsyncScheduleLocked方法中,主要做了两件事:

1)创建VSyncCallbackRegistration。VSyncCallbackRegistration是Scheduler对外提供用于操作与监听VSync信号的组件。

2)将VSyncCallbackRegistration保存到结构体mVsync的registration字段中。
8

2.4 VSyncCallbackRegistration的创建

    VSyncCallbackRegistration是VSyncDispatch的代理类,它提供了请求、更新、取消VSync信号的方法,同时会绑定外部监听VSync信号的方法回调。

    在VSyncCallbackRegistration的构造方法中,会调用VSyncDispatch的registerCallback方法,注册接收软件VSync信号回调。
9

2.5 EventThread初始化

    在EventThread的构造方法中,主要做了两件事:

1)初始化VSyncCallbackRegistration,注册VSync监听回调。

2)创建一个新线程,并在新线程中调用threadMain方法。
10
    在线程启动后,会调用EventThread的threadMain方法。在threadMain方法中,主要做了两件事:

1)循环执行任务,直到不需要执行时,退出循环。

2)在退出循环后,取消当前VSync信号的请求。
11
    在EventThread的threadMain方法中,会循环分发VSync信号,主要做了五件事:

1)从VSync消息队列中获取消息。

2)收集监听VSync信号的EventThreadConnection,并加入到consumers中。

3)调用dispatchEvent方法,分发消息。

4)计算当前状态,根据状态请求或取消下一次VSync信号。

5)如果没有Vsync信号需要分发,线程进入等待状态。
12
    在EventThread的dispatchEvent方法中,会遍历DisplayEventConsumers,并调用EventThreadConnection的postEvent函数,分发消息。
13
    在EventThreadConnection的postEvent方法中,最终会通过BitTube,通过文件描述符向客户端发送数据。
14

二.VSync-sf的申请与分发

1.VSync-sf的申请

    VSync-sf用于控制SurfaceFlinger合成和渲染一帧图像。

    当SurfaceFlinger上帧时(BufferQueue中有新的GraphicBuffer),SurfaceFlinger会触发MessageQueue的scheduleFrame方法。

    在SurfaceFlinger的scheduleFrame方法内部,最终会调用VsyncDispatch的schedule方法。VsyncDispatch的实现类为VSyncDispatchTimerQueue,因此实际调用的是VSyncDispatchTimerQueue的schedule方法。
15
    在VSyncDispatchTimerQueue的schedule方法中,会调用scheduleLocked方法。
16
    在VSyncDispatchTimerQueue的scheduleLocked方法中,主要做了三件事:

1)根据CallbackToken找到所有满足要求的VSyncDispatchTimerQueueEntry。VSyncDispatchTimerQueueEntry是VSyncDispatchTimerQueue中对外部VSync信号请求的封装。

2)遍历调用VSyncDispatchTimerQueue的schedule方法,计算下一次VSync信号的发送时间。

3)对发射时间进行定时,等待下一次VSync信号的发送。
17
    在VSyncDispatchTimerQueue的rearmTimerSkippingUpdateFor方法中,主要做了四件事:

1)遍历获取VSyncDispatchTimerQueue中所有的VSyncDispatchTimerQueueEntry。

2)如果VSyncDispatchTimerQueueEntry无法接受下次VSync信号的分发,如请求方在注册回调后未申请下次的VSync信号的回调,则对VSyncDispatchTimerQueueEntry的唤醒时间进行更新。

3)比较所有VSyncDispatchTimerQueueEntry的唤醒时间,并获取其中的最小值。

4)使用最小唤醒时间的时间戳进行定时。
18
    在VSyncDispatchTimerQueue的setTimer方法中,会调用TimeKeeper的alarmAt方法设置唤醒时间点,在唤醒时间到达后,TimerKeeper会回调VSyncDispatchTimerQueue的timerCallback方法。
19

2.VSync-sf的分发

    当定时时间到达时,TimerKeeper会回调VSyncDispatchTimerQueue的timerCallback方法。
在VSyncDispatchTimerQueue的timerCallback方法方法中,主要做了两件事:

1)遍历CallbackMap找到达到唤醒时间的VSyncDispatchTimerQueueEntry,并封装成Invocation,加入Invocation列表。

2)遍历Invocation列表,通过Invocation获取VSyncDispatchTimerQueueEntry,并调用VSyncDispatchTimerQueueEntry的callback方法分发VSync信号。
20
    在VSyncDispatchTimerQueueEntry的callback方法中,会调用类型为VSyncDispatch::Callback的回调。在MessageQueue在创建VSyncCallbackRegistration时,绑定了MessageQueue::vsyncCallback方法,所以这里的VSyncDispatch::Callback对应的是MessageQueue的vsyncCallback方法。
21
    在MessageQueue的vsyncCallback方法中,主要做了两件事:

1)将唤醒时间的时间戳封装成VsyncId。

2)调用Handler分发消息。
22
    在Handler的dispatchFrame方法中,主要做了两件事:

1)保存VSyncId。

2)调用MessageQueue的Looper,发送消息。
23
    在Handler的sendMessage方法中,最终会回调Handler的handleMessage方法。由于Scheduler继承了MessageQueue,因此在Handler的handleMessage方法的内部,会调用Scheduler的onFrameSignal方法。
24
    在Schdueler的onFrameSignal方法中,主要做了两件事:

1)提交已合成的帧显示在屏幕上。

2)如果提交成功,合成下一帧,并通知有新合成的帧可用。
25

三.VSync-app的申请与分发

1.VSync-app的申请

    VSync-app用于控制App的UI渲染。

    当Choreographer通过FrameDisplayEventReceiver调用scheduleVsync方法时,会触发VSync-app信号的申请。

    在FrameDisplayEventReceiver的scheduleVsync方法中,会调用nativeScheduleVsync方法。
26
    FrameDisplayEventReceiver的nativeScheduleVsync方法对应的native实现为android_view_DisplayEventReceiver的nativeScheduleVsync函数。

    在nativeScheduleVsync函数中,主要做了两件事:

1)获取native层的DisplayEventDispatcher。

2)调用DisplayEventDispatcher的scheduleVsync方法,请求VSync信号。
27
    在DisplayEventDispatcher的scheduleVsync方法中,会调用DisplayEventReceiver的requestNextVsync方法。
28
    在DisplayEventReceiver的requestNextVsync方法中,会调用IDisplayEventConnection的requestNextVsync方法。
29
    IDisplayEventConnection是一个Binder类,对应bn端的实现类为BnDisplayEventConnection。而EventThreadConnection继承自BnDisplayEventConnection,因此实际调用的是EventThreadConnection的requestNextVsync方法。
30
    在EventThreadConnection的requestNextVsync方法中,会调用EventThread的requestNextVsync方法。
31
    在EventThread的requestNextVsync方法中,主要做了三件事:

1)开启硬件VSync信号对软件VSync信号进行校准。

1)标记EventThreadConnection的vsyncRequest,为后续信号分发做准备。

2)唤起EventThread对应的线程继续执行VSync信号的分发。
32
    在EventThread的threadMain中,会通过VSyncCallbackRegistration请求或取消VSync信号。

    如果是请求VSync信号,会调用VSyncCallbackRegistration的schedule方法。在VSyncCallbackRegistration的schedule方法,会调用VSyncDispatch的schedule方法。
33
    之后的流程与VSync-sf信号的申请流程相同。在VSyncDispatchTimerQueue的schedule方法中,会调用scheduleLocked方法。

    在VSyncDispatchTimerQueue的scheduleLocked方法中,主要做了三件事:

1)根据CallbackToken找到所有满足要求的VSyncDispatchTimerQueueEntry。VSyncDispatchTimerQueueEntry是VSyncDispatchTimerQueue中对外部VSync信号请求的封装。

2)遍历调用VSyncDispatchTimerQueue的schedule方法,计算下一次VSync信号的发送时间。

3)对发射时间进行定时,等待下一次VSync信号的发送。
34

2.VSync-app的分发

    当定时时间到达时,TimerKeeper会回调VSyncDispatchTimerQueue的timerCallback方法。

    在VSyncDispatchTimerQueue的timerCallback方法方法中,主要做了两件事:

1)遍历CallbackMap找到达到唤醒时间的VSyncDispatchTimerQueueEntry,并封装成Invocation,加入Invocation列表。

2)遍历Invocation列表,通过Invocation获取VSyncDispatchTimerQueueEntry,并调用VSyncDispatchTimerQueueEntry的callback方法分发VSync信号。
35
    在VSyncDispatchTimerQueueEntry的callback方法中,会调用类型为VSyncDispatch::Callback的回调。在EventThread在创建VSyncCallbackRegistration时,绑定了EventThread::onVsync方法,所以这里的VSyncDispatch::Callback对应的是EventThread的onVsync方法。
36
    在EventThread的onVsync方法中,主要做了三件事:

1)调用makeVSync函数,创建Event。

2)将Event加入到vector<DisplayEventReceiver::Event>中。

3)唤醒等待线程,执行threadMain方法。
37

四.HW-VSync的开启与SW-VSync信号的校准

1.HW-VSync信号的开启时机

1)SurfaceFlinger初始化。

2)连续两次请求VSync-app信号的时间间隔超过750ms。

3)SurfaceFlinger合成后,添加FenceTime到VSyncTracker中导致模型计算误差过大。

2.HW-VSync信号的开启

2.1 SurfaceFlinger初始化时开启HW-VSync信号

    在SurfaceFlinger初始化时,会调用initScheduler方法初始化VSync信号相关的组件。在SurfaceFlinger的initScheduler方法中,会调用setVsyncEnabled方法开启HW-VSync上报。

    SurfaceFlinger的setVsyncEnabled方法在ISchedulerCallback类中定义,SurfaceFlinger继承自ISchedulerCallback,实现了setVsyncEnabled方法。

    在SurfaceFlinger的setVsyncEnabled方法中,会调用setHWCVsyncEnabled方法。
38
    在SurfaceFlinger的setHWCVsyncEnabled方法中,会通过HWComposer开启硬件VSync信号。
39
    在开启HW-VSync信号后,HWComposer会回调SurfaceFlinger的onComposerHalVsync方法接收HW-VSync信号。

    在SurfaceFlinger的onComposerHalVsync方法中,主要做了两件事:

1)通过HAL层的displayId和硬件VSync时间戳获取PhysicalDisplayId。

2)调用Scheduler的addResyncSample方法,添加硬件VSync信号的时间戳作为采样。
40
    在Scheduler的addResyncSample方法中,主要做了三件事:

1)根据PhysicalDisplayId获取VsyncSchedule。

2)将硬件VSync信号封装成TimePoint。

3)调用VsyncSchedule的addResyncSample方法,添加硬件VSync信号作为采样。

41
    在VsyncSchedule的addResyncSample方法中,主要做了两件事:

1)收集硬件VSync信号的时间戳并校准软件VSync信号。

2)根据VSyncController的返回值决定开启还是关闭硬件VSync信号。
42
    如果needsHwVsync为true,则会调用VsyncSchedule的enableHardwareVsync方法。在VsyncSchedule的enableHardwareVsync方法中,会调用enableHardwareVsyncLocked方法。
43
    在VsyncSchedule的enableHardwareVsyncLocked方法中,主要做了两件事:

1)如果硬件VSync信号是从未开启状态变成开启状态,则清除已经计算好的软件VSync信号模型。

2)通知SurfaceFlinger开启硬件VSync信号。
44

2.2 请求VSync-app信号时开启HW-VSync信号

    在申请VSync-app信号的过程中,会调用EventThread的requestNextVsync方法。在EventThread的requestNextVsync方法中,会调用Scheduler的resync方法开启硬件VSync信号对软件VSync信号进行校准。

    在Scheduler的resync方法中,会判断连续两次开启硬件VSync信号的时间间隔是否小于750ms,如果小于,则调用resyncAllToHardwareVsync方法开启硬件VSync信号。
45
    在Scheduler的resyncAllToHardwareVsync方法中,会遍历所有的屏幕设备,并调用resyncToHardwareVsyncLocked方法。
46
    在Scheduler的resyncToHardwareVsyncLocked方法中,会调用VsyncSchedule的startPeriodTransition方法。
1)根据PhysicalDisplayId获取屏幕设备。

2)获取屏幕设备的FPS刷新率信息,进而获取VSync周期(屏幕连续两次刷新的时间间隔)。

3)通知VsyncSchedule更新VSync周期并开启硬件VSync信号。
47
    在VsyncSchedule的startPeriodTransition方法中,主要做了两件事:

1)通知VSyncController更新VSync周期。

2)开启硬件VSync信号。
48
    在VsyncSchedule的enableHardwareVsyncLocked方法中,主要做了两件事:

1)如果硬件VSync信号是从未开启状态变成开启状态,则清除已经计算好的软件VSync信号模型。

2)通知SurfaceFlinger开启硬件VSync信号。
49

2.3 添加FenceTime时开启HW-VSync信号

    Fence时间是Fence创建时刻的时间戳,由于Fence创建时刻的时间戳比采样HW-VSync信号的时间戳更接近HW-VSync信号实际发出的时间,因此在SurfaceFlinger调用composite方法进行合成时,会对Fence时间进行采样。

    在SurfaceFlinger调用composite方法中,主要做了两件事:

1)遍历所有的屏幕设备,为每个屏幕设备计算对应的Fence时间。

2)根据屏幕设备的PhysicalDisplayId,添加对应的Fence时间。
50
    在Scheduler的addPresentFence方法中,主要做了两件事:

1)添加Fence时间,最终会添加到VSyncReactor中参与软件VSync模型的计算。

2)根据返回结果决定是否开启硬件VSync信号(此时可能开启了HW-VSync信号,也可能没有开启)。如果计算后得到的误差过大,会重新开启HW-VSync。
51
    在VSyncReactor的addPresentFence方法中,主要做了两件事:

1)获取Fence创建时刻的时间戳。

2)添加时间戳,计算SW-VSync模型。
52

3.SW-VSync信号的校准

    HW-VSync信号的开启会触发SW-VSync信号的校准。

    在SurfaceFlinger初始化触发HW-VSync信号开启与请求VSync-app信号触发HW-VSync信号开启的过程中,会调用VSyncController的addHwVsyncTimestamp方法。在VSyncReactor的addHwVsyncTimestamp方法中,会调用VSyncPredictor的addVsyncTimestamp方法校准SW-VSync模型。

    在添加FenceTime触发HW-VSync信号开启的过程中,会直接调用VSyncPredictor的addVsyncTimestamp方法校准SW-VSync模型。

    在VSyncReactor的addHwVsyncTimestamp方法中,主要做了三件事:

1)判断屏幕刷新率有没有变化(通常情况下屏幕不发生变化刷新率也不会变)。如果屏幕刷新率发生变化,则先设置屏幕刷新率,再收集屏幕刷新率变化后缓存的时间戳(当屏幕刷新率发生变化,在VSyncPredictor的addVsyncTimestamp方法中添加时间戳会失败,此时会对时间戳进行缓存)。如果屏幕刷新率没有变化,则直接收集当前的时间戳。

2)判断时间戳是否收集完成(默认为6个时间戳)。

3)如果不需要收集额外的时间戳,则关闭对Fence时间的时间戳的收集。
53
    VSyncPredictor的addVsyncTimestamp方法是计算SW-VSync模型的核心。谷歌官方采用一元线性回归分析预测法,通过采样的HW-VSync信号样本(屏幕刷新率),计算对应的SW-VSync信号周期。

// This is a 'simple linear regression' calculation of Y over X, with Y being the
// vsync timestamps, and X being the ordinal of vsync count.
// The calculated slope is the vsync period.
// Formula for reference:
// Sigma_i: means sum over all timestamps.
// mean(variable): statistical mean of variable.
// X: snapped ordinal of the timestamp
// Y: vsync timestamp
//
//         Sigma_i( (X_i - mean(X)) * (Y_i - mean(Y) )
// slope = -------------------------------------------
//         Sigma_i ( X_i - mean(X) ) ^ 2
//
// intercept = mean(Y) - slope * mean(X)
//

    具体的,通过最小二乘法得到一条y=bx+a的拟合曲线。其中,b称为回归系数,a称为截距。SW-VSync模型核心就是这两个参数。

struct Model {
    // 回归系数
    nsecs_t slope;
    // 截距
    nsecs_t intercept;
};

五.总结

54

1.VSync信号的分类

    VSync信号分为两种:硬件VSync信号HW-VSync和软件VSync信号SW-VSync。SW-VSync信号由SW-VSync模型产生。HW-VSync信号负责对SW-VSync模型进行校准。

    系统中分发的VSync信号是SW-VSync信号。SW-VSync信号的分发采用单次申请回调制,一次申请对应一次回调,不申请则没有回调。

2.HW-VSync信号的开启

    三种场景下会开启硬件VSync信号HW-VSync会对软件VSync信号SW-VSync进行校准。

1)SurfaceFlinger初始化。

2)连续两次请求VSync-app信号的时间间隔超过750ms。

3)SurfaceFlinger合成后,添加FenceTime到VSyncTracker中导致模型计算误差过大。

3.SW-VSync模型与计算

    谷歌官方采用一元线性回归分析预测法(最小二乘法),通过采样的HW-VSync信号样本(屏幕刷新率),计算对应的SW-VSync信号周期。最终得到一条y=bx+a的拟合曲线。其中,b称为回归系数,a称为截距。

    SW-VSync模型就是这这条曲线的回归系数和截距。

4.SW-VSync信号的分类

    SW-VSync信号也分为两种:VSync-sf信号和VSync-app信号。VSync-sf信号用于控制SurfaceFlinger的Layer合成,VSync-app信号用于控制App渲染UI。

    VSync-sf信号和VSync-app信号是在SW-VSync信号的基础上通过叠加不同的偏移量产生,这些偏移量被称为VSync相位偏移。由于偏移量不同VSync-sf信号和VSync-app信号的回调时机也不同。

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值