Android屏幕刷新机制

2023-06-01  本文已影响0人  愿天深海

基础知识

CPU、GPU

逐行扫描

屏幕在刷新buffer的时候,并不是一次性扫描完成,而是从左到右,从上到下的一个读取过程,顺序显示一屏的每个像素点,按60HZ的屏幕刷新率来算,这个过程只有16.66666...ms。

image.png

显卡帧率

表示GPU在1s中内可以渲染多少帧到buffer中,单位是fps,这里要理解的是帧率是一个动态的,比如我们平时说的60fps,只是1s内最多可以渲染60帧,假如我们屏幕是静止的,则GPU此时就没有任何操作,帧率就为0.

屏幕刷新频率

屏幕刷新频率:屏幕在1s内去buffer中取数据的次数,单位为HZ,常见屏幕刷新率为60HZ。屏幕刷新率是一个固定值和硬件参数有关。也就是以这个频率发出 垂直同步信号,告诉 GPU 可以往 buffer 里写数据了,即渲染下一帧。

屏幕刷新机制演变过程

单buffer

GPU和显示器共用一块buffer

screen tearing 屏幕撕裂、画面撕裂

当只有一个buffer时,GPU 向 buffer 中写入数据,屏幕从 buffer 中取图像数据、刷新后显示,理想的情况是显卡帧率和屏幕刷新频率相等,每绘制一帧,屏幕显示一帧。而实际情况是,二者之间没有必然的大小关系,如果没有同步机制,很容易出现问题。
当显卡帧率大于屏幕刷新频率,屏幕准备刷新第2帧的时候,GPU 已经在生成第3帧了,就会覆盖第2帧的部分数据。
当屏幕开始刷新第2帧的时候,缓冲区中的数据一部分是第3帧数据,一部分是第2帧的数据,显示出来的图像就会出现明显的偏差,称为屏幕撕裂,其本质是显卡帧率和屏幕刷新频率不一致所导致。

双buffer

安卓4.1之前
基本原理就是采用两块buffer。
GPU写入的缓存为:Back Buffer
屏幕刷新使用的缓存为:Frame Buffer
因为使用双buffer,屏幕刷新时,frame buffer不会发生变化,通过交换buffer来实现帧数据切换。
什么时候就行buffer交换呢,当设备屏幕刷新完毕后到下一帧刷新前,因为没有屏幕刷新,所以这段时间就是缓存交换的最佳时间。
此时硬件屏幕会发出一个脉冲信号,告知GPU和CPU可以交换了,这个就是Vsync信号,垂直同步信号。
不可否认,双缓冲可以在很大程度上降低screen tearing错误,但是呢,还是会出现一些其他问题。

Jank 掉帧

如果在Vsync到来时back buffer并没有准备好,就不会进行缓存的交换,屏幕显示的还是前一帧画面,即两个刷新周期显示的是同一帧数据,称为Jank掉帧。

image.png

发生jank的原因是:在第2帧CPU处理数据的时候太晚了,GPU没有及时将数据写入到buffer中,导致jank的发生。
CPU处理数据和GPU写入buffer的时机比较随意。

Project Butter 黄油工程

安卓4.1
系统在收到VSync信号之后,马上进行CPU的绘制以及GPU的buffer写入。最大限度的减少jank的发生。

image.png

如果显卡帧率大于屏幕刷新频率,也就是屏幕在刷新一帧的时间内,CPU和GPU可以充分利用刷新一帧的时间处理完数据并写入buffer中,那么这个方案是完美的,显示效果将很好。

image.png

由于主线程做了一些相对复杂耗时逻辑,导致CPU和GPU的处理时间超过屏幕刷新一帧的时间,由于此时back buffer写入的是B帧数据,在交换buffer前不能被覆盖,而frame buffer被Display用来做刷新用,所以在B帧写入back buffer完成到下一个VSync信号到来之前两个buffer都被占用了,CPU无法继续绘制,这段时间就会被空着,于是又出现了三缓存。

三buffer

image.png

最大程度避免CPU空闲的情况。

Choreographer

系统在收到VSync信号之后,会马上进行CPU的绘制以及GPU的buffer写入。在安卓系统中由Choreographer实现。

参考文献:
https://juejin.cn/post/7163858831309537294
https://blog.csdn.net/litefish/article/details/53939882
https://www.jianshu.com/p/996bca12eb1d

上一篇下一篇

猜你喜欢

热点阅读