作为一个IOS开发者,日常我们更多的是接触业务,我们做的最多的是addSubView: 等等,那么我们的视图就显示出来了。那么它们是如何显示出来的,计算机内部是如何工作的,其底层原理是什么,有时候会卡顿掉帧,这些又究竟是什么原因?这篇文章来大概讲述一下这些内容。
CPU和GPU
CPU
现代计算机整个系统的运算核心、控制核心
GPU
可进行绘图运算工作的专用微处理器,是连接计算机和显示中断的纽带
可以发现 GPU 内部包含众多的ALU(算术逻辑单元) ,它是计算机内部芯片处理算术运算和逻辑运算的核心,由上图可见GPU 的运算能力远超CPU ,因为GPU处理的是大批量的并发运算,而CPU则更多的是串行的逻辑运算。
计算机渲染原理
首先我们得了解计算机是如何把图像渲染出来的:
现代的屏幕都是通过上述类似逐行扫描而把图像显示到屏幕上,而在其底层则是通过一个 帧缓冲区 映射到 屏幕显示器 上:
计算机系统内部结构:
也就是通过CPU对图像的数据进行处理,交给显示处理器,显示处理器再处理成图像数据存储到帧缓冲区 等待显示控制器的信号,将帧缓冲区的内容同步到显示器。
撕裂和掉帧
我们的屏幕是逐行扫描成像,当扫描到底部就会重新扫描下一帧的内容:
我们或许会看到过这样的情形:
这就是通常所讲的图像撕裂问题,为什么会出现这种撕裂问题呢?
图像显示其本质是拿到图像数据后,GPU进行渲染 -> 存储到帧缓冲区 - > 交给视频控制器 -> 读取帧缓冲区的信息(位图)-> 数模转换(数字信号转换为模拟信号) -> 屏幕逐行扫描显示,当第一帧图像扫描到某个位置的时候,GPU已经拿到新的数据并存到帧缓冲区,这个时候视频控制器就从帧缓冲区扫描的是新拿到的一帧图像,但是屏幕是逐行扫描的,他不会打断仍旧是从中间的位置继续扫描,这样就可能出现断层的现象,导致我们所说的撕裂问题,究其原因就是视频控制器的显示速度超过的GPU处理图形的速度。
为了解决撕裂问题,苹果引入了双缓冲区的概念,进而提出了 Vsync垂直同步技术:
GPU 开辟AB两个缓冲区,并对缓冲区进行同步加锁处理,执行流程就是当A缓冲区拿到第一帧数据,就给A缓冲区加上一把锁,屏幕控制器从A拿到数据并逐行扫描完成,A帧缓冲区解锁,并把屏幕控制器指向B缓冲区,B缓冲区加锁并逐行扫描显示,在屏幕控制器扫描B缓冲区的时候,A缓冲区拿到GPU传过来的新数据,以此类推,解决撕裂问题。
其实仔细观察上述图片我们会发现 双缓冲区+垂直同步会解决撕裂问题,但是A图像本来应该显示一帧,由于CPU和GPU的处理速度问题,导致了A的这一帧显示了两次,从而导致B晚一帧显示出来,这就导致了新的问题 掉帧,掉帧并不是丢失图片,而是屏幕 重复渲染了同一帧的数据。
为了减少掉帧我们并不能解决掉帧问题,只能尽量通过时间偏移来尽量的减少,这个时候苹果提出了新的解决方案:三缓冲区,再开辟 一块缓冲区,三级缓冲区是为了充分利用CPU/GPU的空余时间,开辟ABC三个缓冲区,当A显示到屏幕上,B也渲染好了,C再从GPU拿新的渲染数据,当屏幕和帧缓冲区都弄好了视频控制器再指向帧缓冲区的另外一个,再显示,依次交替,达到减少掉帧的情况。
总结一下就是:
- CPU/GPU渲染流水线耗时过长导致掉帧
- 垂直同步 + 双缓冲区 解决图像撕裂问题,但是会造成掉帧问题
- 三级缓冲区的开辟是为了合理使用CPU/GPU以达到减少掉帧的次数
IOS下的渲染框架
最后补充一下IOS的渲染框架构成:
以及: