【Android性能】【流畅度】概念初识

本文介绍了安卓性能中的流畅度概念,包括帧率与刷新率,阐述了为何屏幕刷新率通常为60Hz。详细解析了渲染流程,特别是双缓冲、垂直同步(VSync)的概念及其作用。当帧速率超过屏幕刷新率时可能导致画面撕裂,反之则可能造成丢帧和卡顿。为解决这些问题,文章提到了三缓冲(TripleBuffer)技术,它可以缓解连续卡顿,但也增加了内存占用。
摘要由CSDN通过智能技术生成

小菜鸡最近想在性能测试方面多了解一些,因此先了解了一下安卓性能中的流畅度相关概念,本文章纯理论概念,暂不涉及对应的代码机制,后面再慢慢补~
主要参考了以下两篇大佬文章,内容可能存在高度重复,仅作为学习记录用,侵删
https://zhuanlan.zhihu.com/p/420329041
https://testerhome.com/topics/29134
初学ing,有理解错误的感谢指出~

一、概念

1.1 帧率与刷新率

帧率 frame rate: 每秒显示帧数,cpu在1s内合成的帧数,单位是fps(frame per second)
刷新率 refresh rate: 屏幕在1s内刷新的次数,单位Hz,Android一般是60Hz

1.2 为什么是60fps?

人眼与大脑之间的协作无法感知超过60fps的画面更新。

二、渲染流程&机制

2.1 渲染一帧画面

在这里插入图片描述

上图表现了渲染一帧画面的全流程,其具体过程如下:

  • 定义布局中的组件;
  • 将ImageView组件解析成ImageView对象加载到内存中;
  • CPU对ImageView对象进行运算处理,获得对应的多维矢量图形;
  • GPU对矢量图进行栅格化处理,获得位图,将位图存入back buffer中;
  • 屏幕渲染完上一帧数据后发出Vsync信号,cpu收到信号后将back buffer的数据复制到frame buffer,屏幕用frame buffer中的数据进行下一帧的渲染。

2.2 Double Buffer

我们先来看看假如没有缓冲的情况,如果没有缓冲,渲染一帧的流程变成了这样:
在这里插入图片描述
屏幕会不停的读取接收到的数据并将其显示出来。
当屏幕刷新率小于帧速率时,即如果屏幕未显示完上一帧时,cpu/gpu已经处理完下一帧,那么屏幕就会读取最新一帧的数据,导致显示出来的上半部分的数据是上一帧的,而下半部分的数据是下一帧的,这就造成了上下画面撕裂的现象。

为了减少此类现象出现,我们引入后缓冲(back buffer)帧缓冲/前缓冲(Frame buffer) 的概念。
back buffer中存放cpu处理好的数据,frame buffer中存放屏幕当前处理的数据,当frame buffer数据渲染完之后,再将back buffer的数据复制过来进行渲染。

但是还是存在一个问题,如果cpu处理的速度非常快,frame buffer的数据还没刷新完毕,back buffer就已经写满,此时若发生复制,则又会产生撕裂的情况!
限制cpu处理速度当然不是明智的选择,因此我们需要找到合理的数据处理方式,确保cpu的数据不会覆盖掉当前屏幕正在写的数据。这就涉及到另一个很重要的概念 —— 垂直同步

2.2 VSync——垂直同步

Vsync(vertical sync),也叫垂直同步,当屏幕渲染完一帧数据后,即将开始渲染下一帧之前,发出的一个同步信号。

为什么要有Vsync?
前面我们提到,即使有了双buffer机制,还是可能存在画面撕裂的情况。产生画面撕裂的本质原因是cpu和屏幕进行数据交换的时机不对,数据的交换应该发生在屏幕渲染完一帧后,而不是cpu写入一帧数据后,也就是说数据交换的时机应该由屏幕决定,而不是cpu。
但是屏幕本身不是控制器,无法控制数据的交换,为了解决这一问题,我们让屏幕只是发出“上一帧已渲染完“的信号,cpu接收到这个信号后,再将back buffer中的数据复制到frame buffer中供屏幕进行下一帧的渲染,这就是所谓“垂直同步”。
在这里插入图片描述
在这里插入图片描述
这里有一个不太理解的,就是上图中cpu的开始时间总是在收到Vsync信号之后,如果是这样cpu不会来不及处理吗?

2.3 Triple Buffer

通过前面的讲述可以了解到,造成撕裂的根本原因是帧速率大于屏幕刷新率,而双buffer和Vsync已经可以完美解决这种撕裂问题,那如果现在帧速率小于屏幕刷新率会发生什么呢?
当发生这种情况时,本质上就是CPU/GPU不能及时处理当前数据导致的。当屏幕显示完上一帧并发出Vsync信号后,cpu当前帧的计算并没有处理完,缓冲区的数据并没有发生改变,这时候屏幕显示的还是上一帧的数据,这就造成了我们平时所看到的丢帧、不流畅的现象。
对于这一点我们没有完美解决的方法,只能尽量对处理流程进行优化,减轻cpu的负担,让其尽量在1个Vsync发送周期内完成相应的工作。关于具体如何从这方面优化卡顿,我们这里暂时先不提,后面专门学了再看。

这里我们关注卡顿中的另一种情况。
下图可知,CPU和GPU并非并行工作的,back buffer本质上是存储GPU处理完的数据的:
在这里插入图片描述

如果此时cpu已经处理完,GPU没有处理完,没有在VSync信号到来时更新back buffer数据,就会发生卡顿。但其中有一个问题,由于cpu处理完的数据没有buffer存放,因此它会等待gpu处理完且收到下一个Vsync信号时才开始处理下一帧。具体如下图:
在这里插入图片描述

我们可以将Display那一行看作是前缓冲,将GPU和CPU两行叠加起来看作是后缓冲(因为它俩排队使用),将VSYNC线隔离开的竖行看作一个帧。
我们看到,在第一帧里面,GPU墨迹了半天没搞完,以至于在第二帧里面,Display(屏幕)显示的还是第一帧的A数据,此时就产生了Jank(卡顿),并且在一个vsync信号过来后,cpu什么都没做,因为gpu占着后缓冲(那个绿色的长B块),所以cpu只能再等下一个vsync,在下一个vsync里面,cpu终于拿到了后缓冲的使用权,但是cpu计算时间比较长,导致了gpu时间不够用,数据又没算完,再次发生了卡顿,可以说,这次卡顿直接受到了第一次卡顿的影响。
试想: 如果在第一次卡顿的时候,cpu也能计算数据,那么,第二次卡顿可能就不存在了,因为cpu已经在第一次卡顿的时候把蓝色的A给计算完了,第二次完全可以让gpu独自计算(绿色的A),就不存在因为排队导致的时间不够用了,但是!cpu和gpu共用后缓冲,这就导致它们只能轮流使用后缓冲.
(摘自 https://zhuanlan.zhihu.com/p/420329041)

通过上面解析我们可以看到:由于cpu没有单独的buffer,它和gpu只能串行工作,导致每一次的丢帧都可能对后续造成影响。为了解决这一问题,我们需要给cpu再加一个单独的buffer,也就是triple buffer,具体如图:
在这里插入图片描述

我们看到,在第一次jank内,cpu使用了第三块缓冲区,自己计算了C帧的数据,假如此时没有三缓冲,那么cpu就只能再继续等下一个vsync信号,也就是在图中蓝色A块的地方,才能开始计算C帧数据,就又引发下一次卡顿。
我们看到,通过引入三缓冲,虽然不能避免卡顿问题,但是却可以大幅优化卡顿问题,尤其是避免连续卡顿.
(摘自 https://zhuanlan.zhihu.com/p/420329041)

triple也有其缺点,就是占用内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值