CPU和GPU
CPU是一个用来控制/处理逻辑复杂的数据的运算核心,它的依赖性非常高,利用时间片切换实现高并发操作。
GPU是一个加速器,是一个对CPU的补充,它的目的就是尽可能的加速图形处理速度。也就是说,对于GPU来说,可能处理某些任务的性能会非常差,甚至有些任务根本就没法在GPU上运行。但是这都不要紧,因为这些任务可以交给CPU做。对于GPU来说,计算问题的体量一般由几百MB到数GB之间,不需要考虑数TB的数据体量的问题。
最大的不同是GPU并不依赖多级Cache来降低对内存访问的延迟。相反,GPU通过大量的多线程来规避了内存延迟对性能的影响。具体来说,在GPU等待内存数据到来的时候,GPU会运行几百到几千个与之前数据不相关的线程。与CPU内存系统相反,GPU的内存系统因此更加面向大的带宽而不是低延迟,而且GPU的内存大小通常要小于CPU。因为大量的并行线程带来了很好的处理带宽,GPU包含了数个平行处理核心并且每个处理核心都可以运行大量的平行线程。因此,GPU的并行运行能力比普通的CPU要大得多。
图像的显示过程
CPU解码->GPU进行渲染->放入帧缓存区->显示控制器读取->数模转化->显示
- 理想情况是:扫描->显示->不断刷新。
- 实际可能是:开始刷新->GPU渲染未完成->缓存区中还是旧缓存->扫描出上一次的缓存,继续扫描->GPU渲染完成->扫描出新缓存->出现图片撕裂的现象。
撕裂发生的前提是CPU以及GPU的计算能力跟不上当前的帧率,此时才可能发生撕裂。
如何解决这个问题呢?
苹果采用的是双缓存+垂直同步信号
双缓存:GPU开辟两个帧缓存区
垂直同步信号:帧缓存去加锁,防止出现撕裂现象
整个流程为:
- A帧缓存区渲染完成->视屏控制器指向A帧缓存区->A帧缓存区加锁.
- 渲染B帧缓存区->B帧缓存区渲染完成
- A帧缓存区扫描完成且B帧缓存区渲染完成,A缓存区解锁->视屏控制器指向B帧缓存区->B缓存区加锁
- 往复进行
我的理解是:当视屏控制器指向某个缓冲区时(正在扫描某个缓存区),该缓存区加锁,视频控制器此时无法改变指向,必须等待此次扫描完成且另一缓存区渲染完成
但同时又会引起一个新的问题:掉帧?
当A帧缓存区中的内容完全显示到屏幕上后,在同一个周期内B帧缓存区并没有完成渲染,视屏控制器就不会指向B帧缓存区,仍指向A缓存区,屏幕继续显示A帧缓存区中的内容,直到B帧缓存区渲染完成。进行下一次刷新时会从B缓存区中读取,这三个周期内显示了两帧的内容,就叫做掉帧。
为了减少掉帧(注意不是解决,掉帧问题只能尽量的减少,而不是解决,三级缓冲区也有可能出现掉帧),引入三级缓存区,三级缓冲区是为了充分利用CPU/GPU的空余时间,开辟ABC三个帧缓冲区,A显示屏幕, B也渲染好,C再从GPU拿取渲染数据,当屏幕缓冲区和帧缓冲区都弄好了,然后视频控制器再指向帧缓冲区的另外一个,再显示,这样交替,达到减少掉帧的情况,这样做就比二级缓冲区多了一个确认的操作
总结:屏幕卡顿原因:
- CPU/GPU 渲染流⽔线耗时过⻓->掉帧
- 垂直同步Vsync + 双缓存区 DoubleBuffering 以掉帧作为代价解决屏幕撕裂
- 三缓存区: 合理使⽤CPU/GPU 减少掉帧次数;