iOS的渲染原理总结(上)

『iOS 渲染原理解析』的阅读总结,写一下学习心得与收获

带着几个问题去阅读这篇优秀的文章,可以收获很多

  1. CPU 和 GPU 的设计目的分别是什么?
  2. CPU 和 GPU 哪个的 Cache\ALU\Control unit 的比例更高?
  3. 计算机图像渲染流水线的大致流程是什么?
  4. Framebuffer 帧缓冲器的作用是什么?
  5. Screen Tearing 屏幕撕裂是怎么造成的?
  6. 如何解决屏幕撕裂的问题?
  7. 掉帧是怎么产生的?

CPU 与 GPU 的架构

644

CPU 中拥有更多的缓存空间 Cache 以及复杂的控制单元,计算能力并不是 CPU 的主要诉求。

GPU 中则拥有更多的计算单元,具有更强的计算能力,同时也具有更多的控制单元

CPU 和 GPU 其设计目标是不同的,它们分别针对了两种不同的应用场景。

CPU 是运算核心与控制核心,需要有很强的运算通用型,兼容各种数据类型,同时也需要能处理大量不同的跳转、中断等指令,因此 CPU 的内部结构更为复杂。

GPU 则面对的是类型统一、更加单纯的运算,也不需要处理复杂的指令,但也肩负着更大的运算任务。

计算机图像渲染流水线的大致流程

CPU 会将图像进行一系列的操作或改变,将最终的图像信息传给 GPU

GPU 的渲染流程图:

pipeline

屏幕成像与卡顿

通过 GPU 渲染结束之后的像素信息,会被存在帧缓冲器(Framebuffer)中,之后视频控制器会读取帧缓冲器中的信息,经过数模转换传递给显示器,进行显示,整个流程如下图所示:

image-20200707150031986

显示器的电子束会从屏幕的左上角开始逐行扫描,屏幕上的每个点的图像信息都从帧缓冲器中的位图进行读取,在屏幕上对应地显示。

每次整个屏幕被扫描完一次,就相当于呈现一帧完整的图像。屏幕不断地刷新,不停呈现新的帧,就能呈现出连续的影像。

这个屏幕刷新的频率,就是帧率(Frame per Second,FPS)。

由于人眼的视觉暂留效应,当屏幕刷新频率足够高时,就能让画面看起来是连续而流畅的。

对于 iOS 而言,app 应尽量保证 60FPS 才是最好的体验

屏幕撕裂

在理想的情况下,一个流畅的图像显示流水线:显示器的电子束对新的一帧进行扫描时,CPU + GPU 对于该帧的渲染应该已经结束,渲染结束的位图已经存在帧缓冲器中。但这种情况是非常脆弱的,很容易产生屏幕撕裂: image-20200707163959897

CPU+GPU 的渲染过程是一个非常耗时的过程。

如果电子束开始扫描新的一帧时,位图还没有渲染好,而是在扫描到屏幕中间才渲染完成,被放入帧缓冲器中,就会出现上图这样的现象:已扫描的部分是上一帧的画面,未扫描的部分是新的一帧图像,从而导致屏幕撕裂

image-20200707201143859

垂直同步 Vsync + 双缓冲机制 Double Buffering

解决屏幕撕裂的一个策略是使用垂直同步信号 Vsync 与双缓冲机制 Double Buffering。

根据苹果的官方文档,iOS 设备会始终使用 Vsync + Double Buffering 的策略。

垂直同步信号(vertical synchronisation,Vsync)相当于给帧缓冲器加锁。

当电子束完成一帧的扫描后,将要从头开始扫描时,就会发出一个垂直同步的信号。只有当视频控制器接收到 Vsync 之后,才会将帧缓冲器中的位图更新为下一帧,这样就能保证每次显示的都是同一帧的画面,因而避免了撕裂。

但是在这种情况下,需要整个 CPU+GPU 的渲染流程都要在一瞬间完成,这明显是不现实的。

image-20200707200010138

双缓冲机制会增加一个新的备用缓冲器(back buffer)。

渲染结果会预先保存在 back buffer 中,在接收到 Vsync 信号时,视频控制器会将 back buffer 中的内容置换到 frame buffer 中,此时就能保证置换操作几乎在一瞬间完成(实际上是内存地址的交换)

掉帧 Jank

启用 Vsync 信号以及双缓冲机制置换,能够解决屏幕撕裂的问题,但是会引入新的问题:掉帧

如果在接收到 Vsync 时,CPU+GPU 还没有渲染好新的位图,视频控制器就不会去替换 frame buffer 中的位图。这时屏幕就会重新扫描呈现上一帧一模一样的画面。相当于两个周期显示了同样的画面,这就是所谓的掉帧情况。

image-20200707200438196

如图所示,A、B 代表两帧缓冲器,当 B 没有渲染完毕时就接收到了 Vsync 信号,所以屏幕只能再显示相同帧 A

屏幕卡顿的本质

手机使用卡顿的直接原因,就是掉帧。当掉帧过多,导致刷新频率(FPS)过低,就会造成不流畅的使用体验

总结一下:

  • 屏幕卡顿的根本原因:CPU 和 GPU 渲染图像过程耗时过长,导致掉帧
  • 垂直同步信号+双缓冲机制的意义:强制同步屏幕刷新,会以掉帧为代价解决屏幕撕裂问题