Android 图形系统(2)---- Android vsyn

2021-03-08  本文已影响0人  特立独行的佩奇

显示系统基础知识

一个典型的图形显示系统包含 CPU,GPU,Display 三个部分,CPU负责计算需要渲染的数据,把计算好的数据交给GPU,GPU会对图形数据进行渲染,渲染好后放到buffer(图像缓冲区)里存起来,然后Display(屏幕或显示器)负责把buffer里的数据呈现到屏幕上。

CPU 和 GPU 的计算是可以并行执行的。

draw display flow.png

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

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

Tearing 与double buffer

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

简单来说就是边画边显示造成的,正在显示的buffer 里的内容被篡改,导致显示画面里的内容不是来自同一帧数据。

Tearing.png

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

double buffer.png

Vsync 机制

Android4.1之前,屏幕刷新也遵循 上面介绍的双缓存+VSync 机制;但是会存在下面的缺陷。

上层的有更新画面的需求时,才会去重新绘制和显示画面;

上层更新画面的时机是不确定的。

draw without vsync.png

问题:
第2个Diplay VSync来时,由于第2帧数据还没有准备就绪,缓存没有交换,显示的还是第1帧。这种情况被Android开发组命名为“Jank”,即发生了丢帧

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

vsync flow.png

总结起来就是只有在vsync 到来之后,才会开始进行帧的渲染和绘制。

draw with vsync.png

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

Triple buffer

这里再考虑CPU和 GPU处理时间超出一个Vsync 的情形

draw beyond 1 vsync.png
  1. 在第二个时间段内,但却因 GPU 还在处理 B 帧,缓存没能交换,导致 A 帧被重复显示

  2. 而B完成后,只有等到下一个vsync 来临才可以显示。

  3. CPU 和 GPU 都是可以多线程执行的,第一个vsync 到来之后,由于没有可以用的buffer,所以CPU和GPU都无法继续绘制下一帧。

如果在double buffer 基础上增加一个,使用triple buffer:

triple buffer.png

第一个Jank,是不可避免的。但是在第二个 16ms 时间段,CPU/GPU 使用 第三个 Buffer 完成C帧的计算,虽然还是会多显示一次 A 帧,但后续显示就比较顺畅了,有效避免 Jank 的进一步加剧。

总结

上一篇下一篇

猜你喜欢

热点阅读