iOS下图形渲染流程
iOS开发中,控件通过渲染显示到屏幕中,那么这些控件是通过怎样的流程去渲染上去的呢?
下面我们从两部分开始介绍:
一 图形渲染技术栈
下图所示为 iOS App 的图形渲染技术栈,App 使用Core Graphics、Core Animation、Core Image
等框架来绘制可视化内容,这些软件框架相互之间也有着依赖关系。这些框架需要通过Metal(iOS12之前是通过OpenGL ES)来调用GPU进行绘制,最后将绘制好的内容显示在屏幕上。
iOS 渲染框架
UIKit
UIKit
是 iOS 开发者最常用的框架,可以通过设置 UIKit
组件的布局以及相关属性来绘制界面。
事实上, UIKit
自身并不具备在屏幕成像的能力,其主要负责对用户操作事件的响应(UIView
继承自 UIResponder
),事件响应的传递大体是经过逐层的 视图树 遍历实现的。
Core Animation
Core Animation
源自于 Layer Kit
,动画只是 Core Animation
特性的冰山一角。
Core Animation
是一个复合引擎,其职责是 尽可能快地组合屏幕上不同的可视内容,这些可视内容可被分解成独立的图层(即 CALayer),这些图层会被存储在一个叫做图层树的体系之中。从本质上而言,CALayer
是用户所能在屏幕上看见的一切的基础。
Core Graphics
Core Graphics
基于 Quartz 高级绘图引擎,主要用于运行时绘制图像。开发者可以使用此框架来处理基于路径的绘图,转换,颜色管理,离屏渲染,图案,渐变和阴影,图像数据管理,图像创建和图像遮罩以及 PDF 文档创建,显示和分析。
当开发者需要在 运行时创建图像 时,可以使用 Core Graphics
去绘制。与之相对的是 运行前创建图像,例如用 Photoshop 提前做好图片素材直接导入应用。相比之下,我们更需要 Core Graphics
去在运行时实时计算、绘制一系列图像帧来实现动画。
Core Image
Core Image
与 Core Graphics
恰恰相反,Core Graphics
用于在 运行时创建图像,而 Core Image
是用来处理 运行前创建的图像 的。Core Image
框架拥有一系列现成的图像过滤器,能对已存在的图像进行高效的处理。
大部分情况下,Core Image
会在 GPU 中完成工作,但如果 GPU 忙,会使用 CPU 进行处理。
OpenGL ES
OpenGL ES
(OpenGL for Embedded Systems,简称 GLES),是 OpenGL 的子集。在前面的 图形渲染原理综述 一文中提到过 OpenGL 是一套第三方标准,函数的内部实现由对应的 GPU 厂商开发实现。
Metal
Metal
类似于 OpenGL ES
,也是一套第三方标准,具体实现由苹果实现。大多数开发者都没有直接使用过 Metal
,但其实所有开发者都在间接地使用 Metal
。Core Animation
、Core Image
、SceneKit
、SpriteKit
等等渲染框架都是构建于 Metal
之上的。
当在真机上调试 OpenGL 程序时,控制台会打印出启用 Metal
的日志。根据这一点可以猜测,Apple 已经实现了一套机制将 OpenGL 命令无缝桥接到 Metal
上,由 Metal
担任真正于硬件交互的工作。
二 CoreAnimation流水线 (Core Animation Pipeline)
Core Animation
,它本质上可以理解为一个复合引擎,主要职责包含:渲染、构建和实现动画。
iOS中我们对每一个UIView
进行布局显示,本质上都是对其关联的CALayer
进行操作,UIView
负责事件的响应,CALayer
负责显示.
iOS中的图形渲染事务都是由Core Animation
提交的.
事实上,app 本身并不负责渲染,渲染则是由一个独立的进程负责,即Render Server
进程。
App 通过 IPC 将渲染任务及相关数据提交给 Render Server
。Render Server
处理完数据后,再传递至 GPU
。最后由 GPU 调用 iOS 的图像设备进行显示。
CoreAnimation
流水线的详细过程如下:
- 首先,由 app 处理事件(
Handle Events
),如:用户的点击操作,在此过程中 app 可能需要更新 视图树,相应地,图层树 也会被更新。 - 其次,app 通过 CPU 完成对显示内容的计算,如:视图的创建、布局计算、图片解码、文本绘制等。在完成对显示内容的计算之后,app 对图层进行打包,并在下一次 RunLoop 时将其发送至
Render Server
,即完成了一次Commit Transaction
操作。 -
Render Server
主要执行Open GL、Core Graphics
相关程序,并调用 GPU - GPU 则在物理层上完成了对图像的渲染。
- 最终,GPU 通过
Frame Buffer
(帧缓存)、视频控制器
等相关部件,将图像显示在屏幕上。
Commit Transaction
在 Core Animation
流水线中,app 调用 Render Server
前的最后一步 Commit Transaction
其实可以细分为 4 个步骤:
Layout
Display
Prepare
Commit
Layout
Layout
阶段主要进行视图构建,包括:LayoutSubviews
方法的重载,addSubview:
方法填充子视图等。
Display
Display
阶段主要进行视图绘制,这里仅仅是设置最要成像的图元数据。重载视图的 drawRect:
方法可以自定义 UIView
的显示,其原理是在 drawRect:
方法内部绘制寄宿图,该过程使用 CPU 和内存。
Prepare
Prepare
阶段属于附加步骤,一般处理图像的解码和转换等操作。
Commit
Commit
阶段主要将图层进行打包,并将它们发送至 Render Server
。该过程会递归执行,因为图层和视图都是以树形结构存在。