iOS视觉(二) -- OpenGL渲染解析

2,189 阅读5分钟

一、CPU与GPU

  • CPU是现代计算机的运算核心,以及计算机的控制核心。CPU会处理非常多的逻辑复杂内容,以及各种数据类型、终端命令等。
  • GPU是计算机中负责图形绘图运算的微处理器,是连接计算机和显示终端的纽带。GPU不擅长处理逻辑复杂的东西,擅长处理单一的计算处理。

1.1、CPU与GPU的架构

CPU拥有ALU计算单元、Control控制单元、高级缓存来协助整个系统的调转。

GPU拥有很多的ALU计算单元,通过计算单元来进行一个高并发的运算。每一个计算单元之间都会连接一个SP流处理器来控制这些计算

二、计算机的显示

2.1、随机扫描显示

显示处理器处理文件后会用电子光束进行自由移动来显示出图形。只能来绘制一些线段,它只有一个光束。所以显示一个图像的时间与图像的复杂度是有关的。

2.2、光栅扫描显示

电子光束从屏幕左上方进行横向向右进行扫描,到达屏幕右边界后从第二行进行再次向右进行扫描。

光栅显示系统的图像是由一个像素阵列来组成的。采用光栅扫描显示一个图像的时间跟图像是没有关系的,每一帧的时间是固定的,与图像复杂度无关。在显示过程中会不断的进行刷新,但是人眼并看到图像是静止不动的,这就是一个视觉暂留的原因导致的,人最低看到每秒16帧就会觉得是连贯的。

2.2.1、光栅扫描显示系统的组成

  • 显示器:用于界面显示,就是屏幕显示器。显示的内容是帧缓存区中的图像数据
  • 视频控制器:控制刷新部件,负责帧缓冲区与显示器的对应关系,让他能进行一个绘制
  • 帧缓存区域:存储颜色值,又叫显存(显示器里需要显示的内容)。

早期的显示器没有显存一说的,所以还是利用了系统的一个缓冲区来进行显示。

目前计算机可以用独立显卡的显存来做缓冲区,通过GPU来处理图像,操作速度会得到极大的提升,并且不再受系统总线的限制。

2.3、屏幕撕裂

渲染流程:GPU进行渲染 -> 帧缓存区里 -> 视频控制器 ->读取帧缓存区信息(位图) -> 数模转换(数字信号转换为模拟信号) -> 显示

每扫描一张图片,就不断的显示一张图片,60FPS看会看到非常流畅的画面。

但是,在渲染的过程中,读取下一次缓冲数据,此时帧缓冲区中还没有完全刷新新的缓冲图像数据,例如缓冲区新的缓冲数据只是更新到一半,此时显示的图像是一部分为旧的缓冲数据,一部分为新的缓冲数据,就会造成如下效果:屏幕撕裂

主要原因是因为GPU与CPU之间的处理时间不是一致所导致的。

所以苹果使用一个解决策略:垂直同步Vsync + 双缓存区DoubleBuffering

  • 垂直同步Vsync:对帧缓冲区加一个锁,只有当当前的扫描扫描完毕后才会进行扫描下一帧数据。主要是为了防止撕裂的情况

  • 双缓存区DoubleBuffering:图片在绘制的时候,先在第一个缓冲区进行读取数据进行绘制,绘制完成后会进入第二个缓冲区进行读取数据进行绘制,结束后再次轮换缓冲区。能从根本上解决撕裂的方式。

2.4、掉帧

启用了这个解决策略之后会产生一个新的问题,就是会产生掉帧的情况:在接收到垂直信号的时候,CPU与GPU还没有准备好图像数据,此时屏幕就拿不到图像数据,这个时候就会发生掉帧,会重复渲染当前缓冲区的重复数据。

此时人们又会使用一个新的策略:三缓冲区。原理与双缓冲区原理一直,但是它也会产生掉帧,但是几率会大大的降低。

掉帧原因:

  1. CPU/GPU渲染流水线耗时过长
  2. 垂直同步Vsync + 双缓存区DoubleBuffering 以掉帧为代价解决屏幕撕裂
  3. 三缓冲区:更合理使用CPU/GPU,减少掉帧次数。

三、OpenGL层的离屏渲染

了解一下我们APP的渲染流程:

OpenGL ES就是用来驱使GPU为为你做显示。我们使用的相关的官方图像框架,就是对OpenGL ES做了一层封装,为我们提供一个载体用来辅助我们使用OpenGL ES。

CoreAnimation本质上是一个复合引擎,主要职责包含:渲染、构建和实现动画。

3.1、View与Layer的关系

无论是iOS开发还是Mac开发,核心动画都是基于APPKit/UIKit的一个layer来进行做的处理。那么View就不会用来处理这些工作。

UIView:

  1. 绘制和动画的载体
  2. 布局,管理子View
  3. 点击事件的处理

CALyer:

  1. 渲染和动画
  2. APPKit/UIKit都要进行渲染,所以不能迎合任何布局

为的是进行职责分离,并且不同的平台的系统交换规则是不一样的。

3.2、渲染流程

任何一个载体(例如:UIButton、UIImage)的加载都来到CoreAnimation, 首先会处理它的事件(点击、改变位置等),然后进行提交Commit Transaction。再对图片提交给Render Server(Core Animation)进行解码,等待下一个Runloop来进行下一个回调。CoreAnimation进行处理后就会提交到OpenGL,OpenGL调度GPU来进行渲染(顶点数据->顶点着色器->片元着色器->等待下一个runloop->显示)

3.2.1、Render Server操作分析

CoreAnimation将数据提交到OpenGL,收到Buffer数据后首先会设置顶点着色器,然后设置片元着色器,最后Render Buffer显示