在App开发的过程中,我们经常会看见屏幕卡顿的现象。比如说极其复杂的cell 1w+这种。这种现象叫做掉帧。这是由于渲染过程中硬件与数据之间数据同步导致的。
名称解释
CPU(Central Processing Unit): 现代计算机整个系统的运算核⼼、控制核⼼。
GPU(Graphics Processing Unit): 可进⾏绘图运算⼯作的专⽤用微处理器,是连接计算机和显示终端的纽带。
显示控制器:直接和屏幕挂钩,负责屏幕上led的明灭
帧缓冲器:存储光栅化后的渲染数据,对应屏幕上每个像素
简单来说CPU,GPU负责数据生成,写入帧缓冲器中,显示控制器从帧缓冲器中拿到渲染数据,负责将数据渲染到屏幕上。数据生产者和屏幕渲染者之间的速度不同,是导致了所有屏幕展示问题的根源。
渲染架构
最开始的架构没有GPU的概念,显示控制器也是由CPU控制,渲染数据放置在内存中。屏幕渲染的速率受CPU,内存和总线的约束。这个时期屏幕上的元素不可能过多,所以分辨率就很低。像当前的1080p Retain屏之类的数据太大,基本不可能使用。
后来引入了GPU专门负责渲染,并从内存中专门开辟了一块区域存储渲染数据。由于这两个硬件专司渲染,当前的成熟架构便将它们放置在一个区域内,从而摆脱了系统总线的依赖。
显示控制器的原理
计算机显示的流程大致可以描述为将图像转化为一系列像素点的排列然后打印在屏幕上,由图像转化为像素点的过程又可以称之为光栅化,就是从矢量的点线面的描述,变成像素的描述。
屏幕的电子枪按照上面方式,从上到下一行行扫描,扫描完成后显示器就呈现一帧画面,随后电子枪回到初始位置继续下一次扫描。
屏幕撕裂与垂直同步
最完美的渲染情况是这样的:GPU将一帧数据放在帧缓冲区中,显示控制器循环扫描完成后,GPU放入下一帧数据。
但是如果GPU在显示控制器扫描的过程中写入了帧缓冲区新数据,那么就屏幕上就会出现上半部分是老图像,下半部分是新图像的撕裂状况。
解决同步问题的根本方法就是加锁,对于撕裂问题,我们可以对在显示控制器开始循环扫描时将帧缓冲区加锁,然后在显示控制器循环扫描结束后进行解锁。
为了把显示器的显示过程和系统的显示控制器进行同步,显示器(或者其他硬件)会用硬件时钟产生一系列的定时信号。当电子枪换到新的一行,准备进行扫描时,显示器会发出一个水平同步信号(horizonal synchronization),简称 HSync;而当一帧画面绘制完成后,电子枪回复到原位,准备画下一帧前,显示器会发出一个垂直同步信号(vertical synchronization),简称 VSync。显示器通常以固定频率进行刷新,这个刷新率就是VSync 信号产生的频率。
我们可以看到,当垂直同步信号发出后,当前一帧已经扫描结束,可以解锁。这种利用垂直同步信号加解锁的技术,就被称为垂直刷新。
双缓冲区与掉帧
之前的帧缓冲区只有一个,如果加锁了,在显示控制器循环扫描的过程中无法读写,这样是对硬件的浪费。因此现在的帧缓冲区一般是两个 A和B。当循环扫描开始,显示控制器从A缓冲区读入数据,此时A缓冲区加锁,B缓冲区此时可以接收GPU的下一帧数据,当扫描完成后,AB交换,显示控制器从B缓冲区读入数据,此时B缓冲区加锁,A缓冲区此时可以接收GPU的下一帧数据。。。。
但是,在扫描完成后,另一个缓冲区不一定可以写完数据,此时屏幕上就会保留上一帧的数据,此时我们就会看见掉帧的现象。