图形渲染

160 阅读4分钟

GPU与CPU

CPU: 计算的运算核心、控制核心;
GPU: 可进行绘制运算的专用微处理器。





屏幕扫描

光栅扫描过程:

屏幕扫描过程是横向一行一行进行的。

扫描显示到屏幕

如上图所示,左侧是帧缓冲区,右侧为显示器。帧缓冲区的是位图。视频控制器经过数模转换将位图显示到屏幕上。

屏幕撕裂

屏幕撕裂类似于下图,屏幕上半部分和下班部分出现撕裂的现象:

那么屏幕撕裂是怎么产生的呢?我们需要先了解下屏幕是如何成像的。

屏幕成像过程

屏幕成像过程

  • 需要显示的图片经过GPU渲染,将渲染后的结果存入帧缓冲区,帧缓冲区存储的为位图;
  • 然后视频控制器从帧缓冲区读取位图;
  • 视频控制器将读取到的位图交给显示器显示,从左上角逐行扫描并显示。

屏幕撕裂原因

  • 在屏幕显示图像的过程中,是不断的从帧缓冲区获取一帧帧的数据显示的;
  • 然后在渲染一帧数据的时候,扫描到一半的时候,也就是一帧数据还没有渲染完成,然后新的一帧数据放入了帧缓冲区;
  • 然后图片下半部分读取的数据就是新一阵的图形数据了,这样就产生了图像上下不匹配,人物、景色错误的现象。 图示如下:

苹果官方的解决方案

苹果针对撕裂现象的解决方方案是:双缓存区+垂直同步。该方案是给帧缓冲区加锁,可以解决撕裂问题。但是会导致新的掉帧问题。
以下是垂直同步+双缓存的一个图解过程,如有描述错误的地方,欢迎留言指出

  • 垂直同步:给帧缓存区加锁,在电子束扫描的过程中,不允许对该帧缓存区进行数据存储;
  • 双缓存区:采用两个帧缓存区用于GPU处理结果的存储,当屏幕显示其中一个缓存区内容时候,另一个缓存区继续等待下一个缓存结果的存入。两个缓存区依次进行交替。

掉帧

采用苹果的双缓存区+垂直同步后引发了新的掉帧问题。掉帧就是屏幕重复显示同一帧数据的情况。

如图所示:当前屏幕显示的是A,当扫描下一帧图像的时候,由于CPU和GPU处理的B还没有准备好,所以扫描显示的仍然是A。

  • 导致掉帧的原因,可能是CPU或者GPU处理超时导致的;
  • 针对掉帧情况,我们可以在采用三缓存区进行优化。三缓存区可以更加合理充分的利用GPU/CPU。三缓存区不能解决掉帧问题,只是减少出现掉帧的次数。

iOS中的渲染

在iOS中的渲染流程如下所示:

  • App通过调用CoreGraphics、CoreAnimation、CoreImage等框架的接口触发图形渲染操作;
  • CoreGraphics、CoreAnimation、CoreImage等框架将渲染交由OpenGL ES,由OpenGL ES来驱动GPU做渲染,最后显示到屏幕上;
  • 由于OpenGL ES 是跨平台的,所以在他的实现中,是不能有任何窗口相关的代码,而是让各自的平台为OpenGL ES提供载体。在ios中,如果需要使用OpenGL ES,就是通过CoreAnimation提供窗口,让App可以去调用。

iOS中渲染框架总结

主要由以下六种框架:

UIView和CALayer的关系

UIView

  • UIView属于UIKit;
  • 负责绘制图形和动画操作;
  • 用于界面布局和子视图的管理;
  • 处理用户的点击事件。

CALayer

  • CALayer属于CoreAnimation;
  • 只负责显示,且显示的是位图;
  • CALayer既用于UIKit,也用于APPKit,UIKit是iOS平台的渲染框架,APPKit是Mac OSX系统下的渲染框架,由于iOS和Mac两个系统的界面布局并不是一致的,iOS是基于多点触控的交互方式,而Mac OSX是基于鼠标键盘的交互方式,且分别在对应的框架中做了布局的操作,所以并不需要layer载体去布局,且不用迎合任何布局方式。

UIView和CALayer的关系

  • UIView基于UIKit框架,可以处理用户触摸事件,并管理子视图;
  • CALayer基于CoreAnimation,而CoreAnimation是基于QuartzCode的。所以CALayer只负责显示,不能处理用户的触摸事件;
  • 从父类来说,CALayer继承的是NSObject,而UIView是直接继承自UIResponder的,所以UIVIew相比CALayer而言,只是多了事件处理功能;
  • 在应用层面来说,需要与用户交互时,使用UIView,不需要交互时,使用两者都可以。

CoreAnimation

我们常常认为CoreAnimation是用来指定动画的,其实它是一个复合引擎,只要的职责是渲染、构建和动画(Render、Compose,and animate)。

  • ios中基于CoreAnimation构建的框架有两个:UIKit和APPKit;
  • CoreAnimation 又是基于Metal 、CoreGraphics封装的。