[070]一文带你看懂Vsync Phase

前言

最近在研究一些跟手性的问题,修改一些vsync phase的值,对这些值有了一些更加深入的理解,感觉还是挺有意思的,写个文章分享给大家。

一、什么是Vsync Phase

手机中有三个vsync 信号,分别是hw vsync,app vsync,sf vsync。
Vsync Phase就是指app vsync,sf vsync和hw vsync之间的相位差。

hw vsync是硬件产生的。
app vsync是基于hw vsync加上一个相位差app phase软件产生的。
sf vsync是基于hw vsync加上一个相位差sf phase软件产生的

1.1 如何查看手机当前的vsync phase

通过以下指令看到app vsync和sf vsync对应的相位差。

19:54 Kobe-Wang:~$ adb shell dumpsys SurfaceFlinger | grep phase
           app phase:      2333334 ns            SF phase:      6166667 ns //正常情况使用
     early app phase:       833334 ns      early SF phase:       666667 ns //切换屏幕帧率的时候使用
  GL early app phase:     15500001 ns   GL early SF phase:      3166667 ns //SF用GPU合成的时候使用。

可以看到总共有三行数据,对应的三组app vsync和sf vsync的相位差参数。

手机会在不同时刻切换三组参数:
app phase和SF phase就是正常情况下使用的。
early app phase和early SF phase是在切换屏幕帧率的时候使用的。
GL early app phase和GL early SF phase是在SF使用GPU合成的时候使用的。

1.2 app phase和SF phase在Trace中的体现

app phase就是红色箭头指的相位差
sf vsync就是绿色箭头指的相位差


二、如何调整手机的相位差

2.1 开启相位差的功能

需要设置这个属性值,否则相位差功能无法生效

[debug.sf.use_phase_offsets_as_durations]: [1]

2.2 调整相位差

调整这6个属性值来调整三组对应的6个相位差。

[debug.sf.late.app.duration]: [20500000]
[debug.sf.late.sf.duration]: [10500000]
[debug.sf.early.app.duration]: [16500000]
[debug.sf.early.sf.duration]: [16000000]
[debug.sf.earlyGl.app.duration]: [21000000]
[debug.sf.earlyGl.sf.duration]: [13500000]

2.3 属性值和相位差的关系

根据属性值计算相位差的关键代码

//vsyncDuration对应vsync周期,60hz手机就是16666666ns
//sfDuration就是对应sf.duration
nsecs_t sfDurationToOffset(std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
    return vsyncDuration - sfDuration.count() % vsyncDuration;
}

//vsyncDuration对应vsync周期,60hz手机就是16666666(纳秒)
//sfDuration就是对应sf.duration
//appDuration就是对应app.duration
nsecs_t appDurationToOffset(std::chrono::nanoseconds appDuration,
                            std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
    return vsyncDuration - (appDuration + sfDuration).count() % vsyncDuration;
}

简单计算一下app phase和SF phase

因为手机是60hz的屏幕,vsyncDuration :16666667
appDuration :[debug.sf.late.app.duration]: [20500000]
sfDuration :[debug.sf.late.sf.duration]: [10500000]

app phase计算
16666667 - (20500000 + 10500000) % 16666667 = 2333334

sf phase计算
16666667 - 10500000 % 16666667 = 6166667

你看最后计算的结果是不是和1.1中用dump指令看到的phase值是一致的。

early app phase和early SF phase以及GL early app phase和GL early SF phase我也就不一一计算了,公式非常简单。

三、调整相位差的好处

如果要知道调整相位差的好处,就要知道三个vsync分别代表什么。
app vsync代表软件开始绘制
sf vsync代表sf开始合成。
hw vsync代表画面开始输出给屏幕

3.1 假如没有相位差

可以看到从app开始绘制到显示到屏幕需要3个vsync周期左右。


那调整相位差可以带来什么好处?

目前我发现的两个作用,提升跟手性或解决app绘制超时带来的丢帧问题。

3.2 提升跟手性

可以从图中看到如果修改了sf的相位差,可以让app开始绘制到显示到屏幕只需要2个vsync周期。但是前提是app绘制要足够快,sf合成要足够快,这样子就提升了跟手性。

算上input中断(120hz采样率),跟手性就需要2.5帧,如果我们在调整app vsync的相位差可以让input中断到画面更新的时间更快,小于2.5帧。

但是如果简单粗暴的按图改,万一app绘制超时了,或者sf合成超时了,反而就是副作用了,会引发一系列的丢帧,buffer堆积的问题,最后就是越改越差。

3.3 解决app绘制超时带来的丢帧问题

这里可能需要引入app的cpu绘制和gpu绘制了,先看如果没有相位差的情况。
可以看到如果没有相位差,因为app绘制超时了,app绘制到屏幕显示需要4帧。


如果调整sf的相位差。

从图中可以看到通过调整了sf的相位差,解决一定程度上app绘制超时导致的丢帧问题。


但是若果app绘制的时间太久了,sf的相位差无法弥补的话,也无法解决问题了,万一sf也超时,反而会带来副作用。原本4帧可以显示的,现在反而5帧了。


3.4 小结

可以看到虽然通过调整相位差可以带来一定的收益,但是其实可能会引发一些意想不到的效果,进行调整的时候一定要谨慎!!!!

四、总结

通过对vsync phase的学习,我发现自己对于一些跟手性问题的分析的能力以及一些丢帧问题的分析比以前有了更深入的理解,非常开心自己又进步了。

五、尾巴

你们可以尝试改一下参数,看看会有什么意外的情况发生。

[debug.sf.late.app.duration]: [20500000]
[debug.sf.late.sf.duration]: [20500000]

参考文献
https://juejin.cn/post/6844903986194022414#heading-20
https://www.jianshu.com/p/df46e4b39428
https://www.jianshu.com/p/824a9ddf68b9

推荐阅读更多精彩内容