Android屏幕刷新机制

一些前置概念

  • 屏幕刷新率

一秒内屏幕刷新的次数(一秒内显示了多少帧的图像),单位 Hz(赫兹),如常见的 60 Hz,90Hz,120Hz(高刷新率)。刷新频率取决于硬件的固定参数(不会变的)。

  • 逐行扫描

显示器并不是一次性将画面显示到屏幕上,而是从左到右边,从上到下逐行扫描,顺序显示整屏的一个个像素点,不过这一过程快到人眼无法察觉到变化。以 60 Hz 刷新率的屏幕为例,这一过程即 1000 / 60 ≈ 16ms。

  • 帧率 (Frame Rate)

表示 GPU 在一秒内绘制操作的帧数,单位 fps。例如在电影界采用 24 帧的速度足够使画面运行的非常流畅。而 Android 系统则采用更加流程的 60 fps,即每秒钟GPU最多绘制 60 帧画面。帧率是动态变化的,例如当画面静止时,GPU 是没有绘制操作的,屏幕刷新的还是buffer中的数据,即GPU最后操作的帧数据。

  • 画面撕裂

一个屏幕内的数据来自2个不同的帧,画面会出现撕裂感,如下图

双缓存

画面撕裂原因

屏幕刷新频是固定的,比如每16.6ms从buffer取数据显示完一帧,理想情况下帧率和刷新频率保持一致,即每绘制完成一帧,显示器显示一帧。但是CPU/GPU写数据是不可控的,所以会出现buffer里有些数据根本没显示出来就被重写了,即buffer里的数据可能是来自不同的帧的, 当屏幕刷新时,此时它并不知道buffer的状态,因此从buffer抓取的帧并不是完整的一帧画面,即出现画面撕裂。

简单说就是在显示的过程中,这个画面显示了不同帧的数据。正常来讲就是一个画面显示一帧的数据,现在这个画面有不同帧的数据,也就导致了画面有一个地方撕裂了。

双缓存

那咋解决画面撕裂呢? 答案是使用 双缓存+VSync

由于图像绘制和屏幕读取 使用的是同个buffer,所以屏幕刷新时可能读取到的是不完整的一帧画面。

双缓存,让绘制和显示器拥有各自的buffer:GPU 始终将完成的一帧图像数据写入到 BackBuffer,而显示器使用 FrameBuffer,当屏幕刷新时,Frame Buffer 并不会发生变化,当Back buffer准备就绪后,它们才进行交换。

VSync

问题又来了:什么时候进行两个buffer的交换呢?

假如是 Backbuffer准备完成一帧数据以后就进行,那么如果此时屏幕还没有完整显示上一帧内容的话,肯定是会出问题的。看来只能是等到屏幕处理完一帧数据后,才可以执行这一操作了。

当扫描完一个屏幕后,设备需要重新回到第一行以进入下一次的循环,此时有一段时间空隙,称为VerticalBlanking Interval(VBI)。那,这个时间点就是我们进行缓冲区交换的最佳时间。因为此时屏幕没有在刷新,也就避免了交换过程中出现 screen tearing的状况。

VSync(垂直同步)是VerticalSynchronization的简写,它利用VBI时期出现的vertical sync pulse(垂直同步脉冲)来保证双缓冲在最佳时间点才进行交换。另外,交换是指各自的内存地址,可以认为该操作是瞬间完成。大概就是下面这幅图的样子

Android屏幕刷新机制

Android4.1之前的问题

具体到Android中,在Android4.1之前,屏幕刷新也遵循上面介绍的 双缓存+VSync 机制。

对于没采用VSYNC做调度的系统来说,比如Project Butter之前的系统(4.1以下),CPU的对于显示帧的处理是凌乱的,优先级也没有保障,处理完一帧后,CPU可能并不会及时处理下一帧,可能会优先处理其他消息,等到它开始处理UI生成帧的时候,可能已经处于VSYNC的中间,这样就很容易跨两个VYSNC信号,导致掉帧。如下图:

以时间的顺序来看下将会发生的过程:

  1. Display显示第0帧数据,此时CPU和GPU渲染第1帧画面,且在Display显示下一帧前完成
  2. 因为渲染及时,Display在第0帧显示完成后,也就是第1个VSync后,缓存进行交换,然后正常显示第1帧
  3. 接着第2帧开始处理,是直到第2个VSync快来前才开始处理的。
  4. 第2个VSync来时,由于第2帧数据还没有准备就绪,缓存没有交换,显示的还是第1帧。这种情况被Android开发组命名为“Jank”,即发生了丢帧
  5. 当第2帧数据准备完成后,它并不会马上被显示,而是要等待下一个VSync 进行缓存交换再显示。

所以总的来说,就是屏幕平白无故地多显示了一次第1帧。

原因是 第2帧的CPU/GPU计算 没能在VSync信号到来前完成 。

我们知道,双缓存的交换 是在Vsyn到来时进行,交换后屏幕会取Frame buffer内的新数据,而实际 此时的Back buffer 就可以供GPU准备下一帧数据了。 如果 Vsyn到来时 CPU/GPU就开始操作的话,是有完整的16.6ms的,这样应该会基本避免jank的出现了(除非CPU/GPU计算超过了16.6ms)。

drawing with VSync

为了优化显示性能,Google在Android 4.1系统中对Android Display系统进行了重构,实现了Project Butter(黄油工程):系统在收到VSync pulse后,将马上开始下一帧的渲染。即一旦收到VSync通知(16ms触发一次),CPU和GPU 才立刻开始计算然后把数据写入buffer。如下图:

CPU/GPU根据VSYNC信号同步处理数据,可以让CPU/GPU有完整的16ms时间来处理数据,减少了jank。

一句话总结,VSync同步使得CPU/GPU充分利用了16.6ms时间,减少jank。

VSYNC+双缓冲在理想情况下是没有问题的,但如果某个环节出现问题,那就不一样了如下(帧耗时超过16ms)如下图:

  1. 在第二个时间段内,但却因 GPU 还在处理 B 帧,缓存没能交换,导致 A 帧被重复显示。
  2. 而B完成后,又因为缺乏VSync pulse信号,它只能等待下一个signal的来临。于是在这一过程中,有一大段时间是被浪费的。
  3. 当下一个VSync出现时,CPU/GPU马上执行操作(A帧),且缓存交换,相应的显示屏对应的就是B。这时看起来就是正常的。只不过由于执行时间仍然超过16ms,导致下一次应该执行的缓冲区交换又被推迟了——如此循环反复,便出现了越来越多的“Jank”。

可以看到在第二个阶段,存在CPU资源浪费,为什么呢?双缓冲Surface只会提供两个Buffer,一个Buffer被DisPlay占用(SurfaceFlinger用完后不会释放当前的Buffer,只会释放旧的Buffer,直观的想一下,如果新Buffer生成受阻,那么肯定要保留一个备份给SF用,才能不阻碍合成显示,就必定要一直占用一个Buffer,新的Buffer来了才释放老的),另一个被GPU处理占用,所以,CPU就无法获取到Buffer处理当前UI,在Jank的阶段空空等待。

三缓存

三缓存就是在双缓冲机制基础上增加了一个 Graphic Buffer 缓冲区,这样可以最大限度的利用空闲时间,带来的坏处是多使用的一个 Graphic Buffer 所占用的内存。

如上图所示,虽然即使每帧需要20ms(CPU 8ms +GPU 12ms),但是由于多加了一个Buffer,实现了CPU跟GPU并行,便可以做到了只在开始掉一帧,后续却不掉帧,双缓冲充分利用16ms做到低延时,三缓冲保障了其稳定性。

以上就是Android屏幕刷新的原理了。

总结

  • 同步是防止画面撕裂的关键,VSYNC同步+双缓冲能防止画面撕裂
  • VSYNC+双缓冲在Android中能有序规划渲染流程,降低延时
  • Android已经采用了双缓冲,双缓冲不仅仅是两份存储,它是一个概念,双缓冲是一条链路,不是某一个环节,是整个系统采用的一个机制,需要各个环节的支持,从APP到SurfaceFlinger、到图像显示都要参与协作。
  • 三缓冲在UI复杂情况下能保证画面的连续性,提高柔韧性。

参考:“终于懂了” 系列:Android屏幕刷新机制—VSync、Choreographer 全面理解!

Android屏幕刷新机制相关推荐

  1. Android屏幕刷新机制—VSync、Choreographer-全面理解

    2.2.3 VSync 问题又来了:什么时候进行两个buffer的交换呢? 假如是 Back buffer准备完成一帧数据以后就进行,那么如果此时屏幕还没有完整显示上一帧内容的话,肯定是会出问题的.看 ...

  2. “终于懂了” 系列:Android屏幕刷新机制—VSync、Choreographer 全面理解!

    文章目录 一.背景和疑问 二.显示系统基础知识 2.1 基础概念 2.2 双缓存 2.2.1 画面撕裂 原因 2.2.2 双缓存 2.2.3 VSync 三.Android屏幕刷新机制 3.1 And ...

  3. Android 屏幕刷新机制

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 这次就来梳理一下 Android 的屏幕刷新机制,把我这段时间因为研究动画而梳理出来的一些关于屏幕刷新方面的知识点分享出来,能力有限 ...

  4. 【屏幕刷新】Android 屏幕刷新机制

    显示系统基础知识 在一个典型的显示系统中,一般包括CPU.GPU.Display三个部分, CPU负责计算帧数据,把计算好的数据交给GPU, GPU会对图形数据进行渲染,渲染好后放到buffer(图像 ...

  5. Android 屏幕刷新机制 VSync+Choreographer

    1.显示系统基础知识 一个典型的显示系统一般包括CPU.GPU.Display三部分,其中CPU负责计算帧数据,并把计算好的数据交给GPU,GPU会对图形数据进行渲染,渲染好后放到图像缓冲区buffe ...

  6. android 卡顿、ANR优化(1)屏幕刷新机制

    前言: 本文通过阅读各种文章和源码总结出来的,如有不对,还望指出 目录 正文 基础概念 视觉暂留 逐行扫描 帧 CPU/GPU/Surface: 帧率.刷新率.画面撕裂 画面撕裂 Android屏幕刷 ...

  7. 屏幕刷新机制小结(九)

    Android刷新机制 SurfaceView理解 一.Android屏幕刷新机制 首先需要了解一些基本概念 在一个显示系统里,一般包括CPU.GPU.Display三部分,CPU负责计算数据,把计算 ...

  8. android屏幕刷新显示机制

    title: android屏幕刷新显示机制 tags: 新建,模板,小书匠 grammar_cjkRuby: true android屏幕刷新显示机制 前言 本文是通过阅读各种文章及代码,总结出来的 ...

  9. Android 显示刷新机制、VSYNC和三重缓存机制

    Android 显示刷新机制.VSYNC和三重缓存机制 为了理解 APP 是如何进行渲染的,我们就必须了解手机硬件是如何工作的,也必须理解什么是 VSYNC. 首先,我们需要了解2个相关概念: 刷新率 ...

最新文章

  1. 8s 接口压力测试_Python Locust 基于Robot Framework实现关键字驱动接口性能测试
  2. postgrepSQL psql基础操作
  3. Linux2.6内核--抢占
  4. swift开源项目精选
  5. 微型项目实践(8):数据访问的实现
  6. ITK:向索引添加偏移量
  7. Java的io类的使用场景
  8. 湖北省仙桃市2021年高考成绩查询,2021年4月湖北仙桃市自考成绩查询时间和有效期是多久?...
  9. 解决 Python fake_useragent 报错 fake-useragent Maximum amount of retries reached问题
  10. memcached 与 redis 的区别和具体应用场景
  11. MDK5软件入门之——基础工程创建及下载和调试
  12. wedo+scratch第一次上课
  13. 『DL笔记』预训练(pre-training/trained)与微调(fine tuning)
  14. linux vsftpd共享位置,文件共享服务之vsftpd
  15. Java类和对象之对象组合之求圆柱体积
  16. selenium模拟登录163邮箱,定位账号及密码输入框问题和iframe嵌套
  17. 笔记本显卡cpu 功耗测试软件,Alienware外星人X系列PK比51M系列性能,谁更强?应该选择买谁?笔记本显卡和CPU功耗如何?...
  18. 蓝桥杯 算法提高 9-2 文本加密(c语言版详细注释)
  19. SLF4J及其MDC详解
  20. 【HTML | CSS | JAVASCRIPT】一款响应式精美简历模板分享(万字长文 | 附源码)

热门文章

  1. 视频去除原声添加新的音乐时如何控制音量大小
  2. 使用Cloud DB构建APP 快速入门 - Android篇
  3. 鸿蒙os 2.0玩吃鸡,华为鸿蒙OS2.0[敏感词汇屏蔽]能简测:极致画质下的吃鸡王者更胜EMUI11...
  4. python井字棋游戏代码_Python实现的井字棋(Tic Tac Toe)游戏示例
  5. Python_子类调用父类的方法
  6. 戴尔540服务器光驱在什么位置,戴尔Dell 500 官方拆机图解教程
  7. 基于SpringBoot零食销售系统的设计与实现【Java毕业设计·安装调试·代码讲解·文档报告】
  8. 书生云王东临:从大型机到超融合 细数企业IT架构的四代技术
  9. 蜗牛星际改内存_蜗牛星际C款双I211网卡4G内穿13SATA开箱及网卡测试
  10. 不变的就是变化本身(Vue学习笔记one)