问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Android VSync机制详解:从基本概念到具体实现

创作时间:
作者:
@小白创作中心

Android VSync机制详解:从基本概念到具体实现

引用
CSDN
1.
https://blog.csdn.net/m0_46208463/article/details/138279546

VSync(垂直同步)是Android系统中一个重要的机制,它负责控制屏幕的刷新和图像的绘制,以确保画面的流畅性和稳定性。本文将详细介绍VSync的基本概念、工作原理以及在Android系统中的具体实现,帮助开发者更好地理解这一机制。

基本概念

  • 帧率(Frame Rate):帧率是一个软件的概念,单位是FPS(Frame Per Second),表示CPU/GPU在一秒内绘制合成产生的帧数。例如,60FPS指的是每秒产生60个画面。

  • 屏幕刷新率(Screen Refresh Rate):屏幕刷新率是一个硬件的概念,单位是Hz(赫兹),表示屏幕硬件刷新画面的频率。例如,60Hz意味着屏幕在1秒内会刷新显示内容60次。

  • VSync(垂直同步):在Android系统中,VSync信号分为两种:屏幕产生的硬件VSync和由SurfaceFlinger转换成的软件Vsync信号。后者通过Binder传递给Choreographer。硬件VSync是一个脉冲信号,用于触发某种操作。

VSync原理

在一个典型的显示系统中,主要包括CPU、GPU和Display三个部分。CPU负责计算帧数据,GPU负责图形渲染,Display负责将Buffer中的数据呈现到屏幕上。

单缓存

在没有引入VSync的情况下,屏幕显示图像的工作流程如下:

理想情况下,帧率和刷新频率相等,每绘制一帧,屏幕显示一帧。但实际情况中,如果没有锁来控制同步,很容易出现问题:

  1. 屏幕刷新率比系统帧率快时,会导致一帧显示多次,造成卡顿。
  2. 系统帧率比屏幕刷新率快时,会导致图像撕裂(tearing)现象。

双缓存+Vsync

为了解决上述问题,引入了双缓冲机制。硬件层提供两个Buffer:一个用于屏幕显示(Frame Buffer),另一个用于后台的CPU/GPU图形绘制与合成(Back Buffer)。

双缓冲的工作流程如下:

  1. 在某个时间点,一个屏幕刷新周期完成,进入短暂的刷新空白期。
  2. VSync信号产生,先完成复制操作,然后通知CPU/GPU绘制下一帧图像。
  3. 复制操作完成后屏幕开始下一个刷新周期,即将刚复制到Frame Buffer的数据数据显示到屏幕上。

在这种模型下,只有当VSync信号产生时,CPU/GPU才会开始绘制。这样,当帧率大于刷新频率时,帧率就会被迫跟刷新频率保持同步,从而避免“tearing”现象。

Drawing with Vsync

为了优化系统显示性能,Google在Android 4.1系统中引入了Project Butter(黄油工程),其中很重要的一点修改就是实现了Drawing with Vsync。在系统收到VSync信号后,CPU和GPU马上开始进行下一帧画面数据的处理,完成后及时将数据写入到Back Buffer中。

但是,如果CPU/GPU处理时间较长,超过了16.6ms,仍然会导致jank(掉帧)问题。

三缓存 + Vsync

为了解决上述问题,引入了三缓冲机制。在双缓冲机制基础上增加一个Graphic Buffer缓冲区,这样可以最大限度地利用空闲时间。

三缓冲虽然不能完全避免卡顿问题,但可以大幅优化卡顿问题,尤其是避免连续卡顿。

Choreographer

Choreographer的引入,主要是为了配合系统Vsync垂直同步机制,给上层App的渲染提供一个稳定的Message处理的时机。Choreographer扮演Android渲染链路中承上启下的角色:

  • 承上:负责接收和处理App的各种更新消息和回调,等到Vsync到来的时候统一处理。
  • 启下:负责请求和接收Vsync信号。

一般应用App有界面UI的变化时,最终都会调用走到ViewRootImpl#scheduleTraversals()方法中,该方法中会往Choreographer中放入一个CALLBACK_TRAVERSAL类型的绘制任务。

Choreographer在收到的绘制任务后,其内部的工作流程如下:

  1. View#invalidate触发更新视图请求,此动作会调用ViewRootImpl#scheduleTraversals函数
  2. ViewRootImpl#scheduleTraversals中会向Choreographer中postCallback放入一个CALLBACK_TRAVERSAL类型绘制待执行任务;
  3. Choreographer通过DisplayEventReceiver向系统SurfaceFlinger注册下一个VSync信号;
  4. 当底层产生下一个VSync消息时,将该信号发送给DisplayEventReceiver,最后传递给Choreographer;
  5. Choreographer收到VSync信号之后,向主线程MessageQueue发送了一个异步消息;
  6. 最后,异步消息的执行者是跑在主线程中的ViewRootImpl#doTraversal,也就是真正开始绘制一帧的操作(包含measure、layout、draw三个过程);

至此,底层的VSync控制上层绘制的逻辑就解释完了。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号