Android 系统每隔 16ms 发出 VSYNC 信号,触发对 UI 进行渲染,VSync 是 Vertical Synchronization(垂直同步)的缩写,是一种在PC上很早就广泛使用的技术,可以简单的把它认为是一种定时中断。而在 Android 4.1(JB) 中已经开始引入 VSync 机制,用来同步渲染,让AppUI 和 SurfaceFlinger 可以按硬件产生的 VSync 节奏进行工作。在整个 Android 视图绘制渲染流程中,VSync 信号都扮演着非常重要的作用,下面简单梳理一下 VSync 信号处理的流程。

一、基本概念

1,帧率(frame rate)
代表了GPU在一秒内绘制操作的帧数,即:GPU 生成帧的速率,单位:fps,如:60 fps。
2, 屏幕刷新率(refresh rate)
代表了屏幕在一秒内刷新屏幕的次数,即:设备刷新屏幕的频率,这取决于硬件的固定参数,单位:Hz,如:60Hz。
(注:对于一个特定的设备,帧率和刷新频率没有必然的大小关系。)

屏幕的刷新过程是每一行从左到右(行刷新,水平刷新,Horizontal Scanning),然后从上到下(屏幕刷新,垂直刷新,Vertical Scanning)。当整个屏幕刷新完毕,即一个垂直刷新周期完成,此时会有短暂的空白期,这时会发出 VSync 信号。

二,vsync 概述

Android 系统中有 2 种 VSync 信号:屏幕产生的硬件 VSync 信号、由 SurfaceFlinger 将其转成的软件 Vsync 信号。其中,硬件 VSync 是一个脉冲信号,起到开关或触发某种操作的作用。软件 VSync 信号经由 Binder 传递给 Choreographer。

1,单缓存

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

CPU/GPU 向 Buffer 中生成图像,屏幕从 Buffer 中取图像、刷新后显示。这是一个典型的生产者——消费者模型。

此时,理想的情况是帧率和刷新频率相等,即:每绘制一帧,屏幕显示一帧。但实际上,二者之间没有必然的大小关系,如果没有锁来控制同步,很容易出现问题。例如:当帧率大于刷新频率,此时屏幕还没有刷新第 n-1 帧时,GPU 已经在生成第 n 帧了,从上往下开始覆盖第 n-1 帧的数据,当屏幕开始刷新第 n-1 帧的时候,Buffer 中的数据上半部分是第 n 帧数据,而下半部分是第 n-1 帧的数据,则显示出来的图像就会出现上半部分和下半部分有明显偏差的现象,我们称之为 “tearing(撕裂)”,如下图:

2、双重缓存(Double Buffer)

为了解决单缓存的“tearing(撕裂)”问题,双重缓存和 VSync 机制应运而生。双重缓存模型如下图:

两个缓存区分别为:Back Buffer 和 Front Buffer(或 Frame Buffer)。GPU 向 Back Buffer 中写数据,屏幕从 Frame Buffer 中读数据。VSync 信号负责调度从 Back Buffer 到 Frame Buffer 的复制操作,可认为该复制操作在瞬间完成(注:其实,该复制操作是等价后的效果,实际上双缓冲的实现方式是:交换 Back Buffer 和 Frame Buffer 内存地址名),所以可认为是瞬间完成。

双缓冲的模型下,工作流程如下:
在某个时间点,一个屏幕刷新周期完成,进入短暂的刷新空白期。此时,VSync 信号产生,先完成复制操作(即:交换),然后通知 CPU/GPU 绘制下一帧图像,同时将刚复制到 Frame Buffer 的数据显示到屏幕上,屏幕开始下一个刷新周期。
在这种模型下,只有当 VSync 信号产生时,CPU/GPU 才会开始绘制。这样,当帧率大于刷新频率时,帧率就会被迫跟刷新频率保持同步,从而避免了“tearing”现象。

注意:通常来说,帧率大于刷新频率只是一种理想的状况,在超过 60fps 的情况下,GPU所产生的帧数据会因为等待 VSYNC 的刷新信息而被Hold住,这样能够保持每次刷新都有实际的新的数据可以显示。但是我们遇到更多的情况是帧率小于刷新频率。

当 VSync 信号发出时,如果 GPU/CPU 正在生产帧数据,此时不会发生复制操作。屏幕进入下一个刷新周期时,从 Frame Buffer 中取出的是“老”数据,而非正在产生的帧数据,即:两个刷新周期显示的是同一帧数据,这就是发生了所谓的“掉帧”现象(Dropped Frame 或 Jank)。

3、三重缓存(Triple Buffer)

上述双重缓存的缺陷在于:当 CPU/GPU 绘制一帧的时间超过 16.67 ms (1/60s) 时,会产生 Jank。更要命的是,产生 Jank 的那一帧的显示期间,GPU/CPU 都是在闲置的。 于是就有了三重缓存:

三重缓存工作原理,与双重缓存类似,只是多了一个 Back Buffer。
注意:第三个缓存并不是总是存在的,只要当需要的时候才会创建。之所以这样,是因为三重缓存会显著增加用户输入到显示的延迟时间。

三、SurfaceFlinger

1、SurfaceFlinger 启动流程
SurfaceFlinger 自身拥有独立进程,由 init 进程启动,如下:

#frameworks/native/services/surfaceflinger/surfaceflinger.rcservice surfaceflinger /system/bin/surfaceflingerclass core animationuser systemgroup graphics drmrpc readproconrestart restart zygote    // 挂掉后会重启 Zygotewritepid /dev/stune/foreground/tasks...

然后执行 main_surfaceflinger 对应的 main() 函数,如下:

#frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
int main(int, char**) {...// 限制binder线程池中线程数最多不超过4,加上主线程一个5个ProcessState::self()->setThreadPoolMaxThreadCount(4);// 启动线程池sp<ProcessState> ps(ProcessState::self());ps->startThreadPool();// 创建SurfaceFlinger,执行SF::onFirstRef,最终调用MessageQueue.cpp::init()方法创建Handler、Loopersp<SurfaceFlinger> flinger = DisplayUtils::getInstance()->getSFInstance();
...// 客户端连接前的一系列初始化操作,包括:初始化DispSyncSource,以及EventThread(有两个:mEventThread对应app,mSFEventThread对应SurfaceFlinger),并初始化显示设备。flinger->init();
...// surfaceFlinger 执行主线程的run()方法,waitForEvent等消息,接受invalidate消息,并开始对应工作流。flinger->run();return 0;
}

到这里,从主线程上看,SurfaceFlinger进程就已经启动了。

2、SurfaceFlinger 处理 VSync 信号
VSync 信号的产生有两种来源,一种是硬件,一种是软件模拟,目前基本都是硬件产生的,硬件源就是 HWComposer,它属于HAL(硬件抽象层)的类,主要就是把硬件 VSync 信号传递到上层来。VSync 的分发流程如下:

VSync 信号的主要作用:同步 应用层的视图绘制任务 和 Native层的视图合成任务。整个过程如下:

(1)VSync产生:HWComposer 作为硬件 VSync 信号。
(2)VSync处理:周期性地唤醒 DipsSyncThread 产生虚拟化的 VSync 信号。
(3)VSync注册与回调:EventThread 负责注册 App、SurfaceFlinger 的 VSync 请求和分发 DipsSyncThread 产生的虚拟化 VSync 信号到 App、SurfaceFlinger。
总结:VSync 信号原则就是:App、SurfaceFlinger 按需请求,按请求分发。

四、App、SurfaceFlinger 的 VSync 信号的请求与接收过程

App 的注册和回调都是通过 Choreographer,它主要负责:input、animation、traversals。
1、App 端
(1)请求 vsync-app:
Choreographer postCallback 发起 vsync 请求,最终调用 FrameDisplayEventReceiver#scheduleVsync,然后进入 native 层,执行 DisplayEventReceiver::requestNextVsync(),最终通过一个 BpDisplayEventConnection 来发起 requestNextVsync 操作。
该过程简单理解为:为客户端和底层建立了一个 connection 连接,通过这个 connection,向 EventThread 注册一个 callback:
(2)接收 vsync-app:
DipsSyncThread 周期性转发 vsync 给 EventThread 上注册的 callback,经过层层回调,App端最终通过 FrameDisplayEventReceiver#onVsync 来接收回调,但不是立即执行,而是通过 Handler.sendMessagerAtTime 加入消息池等待调度。调度到了执行其 run() 方法,走 doFrame 回调流程,如下:
2、SurfaceFlinger 端
(1)请求 vsync-sf:
触发请求 vsync 位置在 SurfaceFlinger.cpp 中的两个方法:

// 事务变化(如:增加window,window大小变化等)
void SurfaceFlinger::signalTransaction() {mEventQueue.invalidate();
}// layer发生变化,主要发生在queueBuffer的时候
void SurfaceFlinger::signalLayerUpdate() {mEventQueue.invalidate();
}

另外还有一个 refresh 方法,表示需要刷新屏幕,一般为处理完事务后,发现需要重新绘制的时候触发该方法:

void surfaceFlinger::signalRefresh() {mEventQueue.refresh();
}

MessageQueue 执行 invalidate 最终还是建立 connection,向 EventThread 注册一个 callback:

void MessageQueue::invalidate() {mEvents->requestNextVsync();
}

总结:SurfaceFlinger 触发请求 vsync 请求的触发点比较分散,简言之,页面变化引起重绘的地方,就会触发 vsync 请求。

(2)接收 vsync-sf:
EventThread 传递 Invalidate 消息给 SurfaceFlinger 主线程 run() 方法 waitForEvent 来执行:

附录:
(1)VSync 机制的详细说明

vsync 信号处理相关推荐

  1. Android SurfaceFlinger 学习之路(五)----VSync 工作原理

    原址 VSync信号的科普我们上一篇已经介绍过了,这篇我们要分析在SurfaceFlinger中的作用.(愈发觉得做笔记对自己记忆模块巩固有很多帮助,整理文章不一定是用来给别人看的,但一定是为加强自己 ...

  2. VSYNC+三重缓存机制+Choreographer

    从 Android 4.1 开始,谷歌在黄油计划中,引入了了三个核心元素,即 VSYNC.Triple Buffer 和 Choreographer. 在一个典型的显示系统中,一般包括CPU.GPU. ...

  3. Android显示系统详解

    一.显示系统的分类: 我们来思考一个问题:从普通用户角度来说,某个APP页面(例如购物APP首页)是怎么被显示到屏幕的? 首先看到的是物理屏幕,然后是屏幕中软件工程师编写的APP页面,也就是手机屏幕驱 ...

  4. 深入Android系统(十二)Android图形显示系统-2-SurfaceFlinger与图像输出

    最近有些忙,切实体验了一把拖更的羞耻感 ( *︾▽︾) 本文和上一篇深入Android系统(十二)Android图形显示系统-1-显示原理与Surface关系比较密切,撸完前篇更易理解本文啦 (๑‾ ...

  5. TTL RGB信号相关 介绍最为详细 HSYNC VSYNC DE CLK

    只要是数字信号处理电路,就必须有时钟信号.在液晶面板中,像素时钟是一个非常重要的时钟信号.像素时钟信号的频率与液晶面板的工作模式有关,液晶面板分辨率越高,像素时钟信号的频率也越高.在一行内,像素时钟的 ...

  6. GPU上的图像和信号处理

    GPU上的图像和信号处理 NVIDIA Performance Primitives(NPP)库提供GPU加速的图像,视频和信号处理功能,其执行速度比仅CPU实施快30倍.拥有5000多个用于图像和信 ...

  7. 广泛的信号处理链如何让语音助理“正常工作”

    广泛的信号处理链如何让语音助理"正常工作" How extensive signal processing chains make voice assistants 'just w ...

  8. 数字信号处理实验三用fft对信号作频谱分析_机器学习中的音频特征:理解Mel频谱图...

    如果你像我一样,试着理解mel的光谱图并不是一件容易的事.你读了一篇文章,却被引出了另一篇,又一篇,又一篇,没完没了.我希望这篇简短的文章能澄清一些困惑,并从头解释mel的光谱图. 信号 信号是一定量 ...

  9. 嵌入式开发之信号采集同步---VSYNC和HSYNC的作用以及它们两者之间的关系

    VSYNC和HSYNC的作用以及它们两者之间的关系 VSYNC和HSYNC的作用以及它们两者之间的关系 VSYNC和HSYNC是什么 VSYNC: vertical synchronization,指 ...

最新文章

  1. 邮件服务器postfix+cyrus
  2. 机器学习-特征工程中的数据预处理
  3. Combo box的使用
  4. DeepWriterID:不依赖书写内容的书写人识别
  5. 用html编写输出今天是星期几,利用Date对象编写程序,判断并输出今天是开学的第几周,星期几。...
  6. python的tkinter按钮大小_如何使用python更改tkinter中按钮和帧的字体和大小?
  7. LayaAir 文本 Text API 详解
  8. 文件上传下载--DiskFileUpload
  9. tongweb自动部署_将web应用迁到TongWeb
  10. 刷机后IMEI丢失如何能刷回来
  11. ios 原生android系统下载地址,iOS原生系统自带分享
  12. 金银猫 服务器维护,金银猫案情进展 投资者可在网上登记报案
  13. 希捷为 Xbox 更新 Game Drive SSD 具有新外观和内部结构
  14. (语法糖)ES6类class声明类的方式 -ES5类声明继承
  15. 阿里云服务器自动签到,天翼云盘自动签到+抽奖,每天至少获得150MB存储空间
  16. kubernetes基础之docker file文件详解(百分之百空手接白刃篇)
  17. python爬取考研成绩什么时候出来_Python 爬取揭秘,你的考研调剂对手就有谁?...
  18. 关于芯片验证的感悟3
  19. Cadence Allegro 如何批量替换过孔?
  20. 桌面快捷方式图标显示问题

热门文章

  1. Baidu Apollo代码解析之Lattice Planner
  2. C4D常用14款插件
  3. android sql语句博客,通过SQL语句查询
  4. 我的大学生活-1-23-毕堃
  5. 关于使用Axis2 webservice 处理Fault响应时抛org.apache.axis2.AxisFault的分析
  6. 分享 19 个免费好用的 CSS 代码样式生成器工具
  7. class文件运行过程
  8. 尚硅谷vue笔记 详细讲解版(尚硅谷 天禹老师)
  9. DHT11型温湿度传感器的使用(附源码)
  10. 使用Aspose.Cells导出excel