iOS 渲染框架

UIKit

UIKit是iOS开发最经常使用的框架,能够经过设置UIKit组件的布局以及相关属性来绘制界面。
事实上,UIKit自身并不具有在屏幕成像的能力,其主要负责对用户操做事件的响应(UIView继承自UIResponder),事件响应的传递大致是通过逐层的视图树遍历实现的。ios

Core Animation

Core Animation源自于Layer Kit,动画只是Core Animation的冰山一角。 Core Animation是一个复合引擎,其职责是尽量快地组合屏幕上不一样的可视内容,这些可视内容可被分解成独立的图层(即CALayer),这些图层会被存储在一个叫作图层树的体系之中。从本质上而言,CALayer是用户所能在屏幕上看见的一切的基础。缓存

Core Graphics

Core Graphics基于Quartz高级绘图引擎,主要用于运行时绘制图像。开发者可使用此框架来处理基于路径的绘图,转换,颜色管理,离屏渲染,图案,渐变和阴影,图像数据管理,图像建立和图像遮罩以及PDF文档建立,显示和分析。bash

当开发者须要在运行时建立图像时,可使用Core Graphics去绘制。与之相对的是运行前建立图像,例如用Photoshop提早作好图片素材直接导入应用。相比之下,咱们更须要Core Graphics去在运行时实时计算、绘制一系列图像帧来实现动画。app

Core Image

Core ImageCore Graphics偏偏相反,Core Graphics用于在运行时建立图像,而Core Image用于处理运行前建立的图像。Core Image框架拥有一系列现成的图像过滤器,能对一寸照的图像进行高效的处理。
大部分状况下,Core Image会在GPU中完成工做,若是GPU忙,会使用CPU进行处理。框架

OpenGL ES

OpenGL ESOpenGL的子集。在图形渲染原理一文中提到过OpenGL是一套第三方标准,函数的内部实现由对应的GPU厂商开发实现。OpenGL / OpenGL ES入门篇,请参考OpenGL/OpenGL ES 入门:图形API以及专业名词解析等系列文章函数

UIView与CALayer的关系

CALayer事实上是用户所能在屏幕上看见的一切的基础。为何UIKit中的视图可以呈现可视化内容,就是由于UIKit中的每个UI视图控件其实内部都有一个关联的CALayer,即backing layer
因为这种一一对应的关系,视图层级有用视图树的树形结构,对应CALayer层级也拥有图层树的树形结构。oop

其中,视图的职责是建立并管理图层,以确保当子视图在层级关系中添加或被移除时,其关联的图层在图层树中也有相同的操做,即保证视图树和图层树在结构上的一致性。布局

为何iOS要基于UIView和CALayer提供两个平行的层级关系呢?post

其缘由在于要作职责分离,这样也能避免不少重复代码。在iOS和Mac OSX两个平台上,事件和用户交互有不少地方的不一样,基于多点触控的用户界面和基于鼠标键盘的交互有着本质的区别,这就是为何iOS有UIKitUIView,对应Mac OSX有AppKitNSView的缘由。它们在功能上很类似,可是在实现上有着显著的区别。动画

实际上,这里并非两个层级关系,而是四个。每个都扮演着不一样的角色。除了视图树图层树,还有呈现树渲染树

CALayer
那么为何CALayer能够呈现可视化内容呢?由于CALayer基本等同于一个纹理。纹理是GPU进行图像渲染的重要依据。

图形渲染原理中提到纹理本质上就是一张图片,所以CALayer也包含一个contents属性指向一块缓存区,称为backing store,能够存放位图(Bitmap)。iOS中将该缓存区保存的图片称为寄宿图

图形渲染流水线支持从顶点开始进行绘制(在流水线中,顶点会被处理生成纹理),也支持直接使用纹理(图片)进行渲染。相应地,在实际开发中,绘制界面也有两种方式: 一种是手动绘制;另外一种是使用图片

对此,iOS中也有两种相应的实现方式:

  • 使用图片:contents image
  • 手动绘制:custom drawing

Contents Image
Contents Image是指经过CALayercontents属性来配置图片。然而,contents属性的类型为id,在这种状况下,能够给contents属性赋予任何值,app仍能够编译经过。可是在实践中,若是contents的值不是CGImage,获得的图层将是空白的。

既然如此,为何要将contents的属性类型定义为id而非CGImage。由于在Mac OS系统中,该属性对CGImageNSImage类型的值都起做用,而在iOS系统中,该属性只对CGImage起做用。

本质上,contents属性指向的一块缓存区域,称为backing store,能够存放bitmap数据。

Custom Drawing
Custom Drawing是指使用Core Graphics直接绘制寄宿图。实际开发中,通常经过继承UIView并实现-drawRect:方法来自定义绘制。

虽然-drawRect:是一个UIView方法,但事实上都是底层的CALayer完成了重绘工做并保存了产生的图片。 下图所示为drawRect:绘制定义寄宿图的基本原理

  • UIView有一个关联图层,即CALayer
  • CALayer有一个可选的delegate属性,实现了CALayerDelegate协议。UIView做为CALayer的代理实现了CALayerDelegate协议。
  • 当须要重绘时,即调用-drawRect:CALayer请求其代理给予一个寄宿图来显示。
  • CALayer首先会尝试调用-displayLayer:方法,此时代理能够直接设置contents属性。
- (void)displayLayer:(CALayer *)layer;
复制代码
  • 若是代理没有实现-displayLayer:方法,CALayer则会尝试调用-drawLayer:inContext:方法。在调用该方法前,CALayer会建立一个空的寄宿图(尺寸由boundscontentScale决定)和一个Core Graphics的绘制上下文,为绘制寄宿图作准备,做为ctx参数传入。
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
复制代码
  • 最后,有Core Graphics绘制生成的寄宿图会存入backing store

Core Animation 流水线

介绍一下Core Animation流水线的工做原理:

事实上,app自己并不负责渲染,渲染则是由一个独立的进程负责,即 Render Server进程。

App经过IPC将渲染任务及相关数据提交给Render ServerRender Server处理完数据后,再传递至GPU。最后由GPU调用iOS的图像设备进行显示。

Core Animation流水线的详细过程以下:

  • 首先,由app处理事件(Handle Events),如:用户点击操做,在此过程当中app可能须要更新视图树,相应地,图层树也会被更新。
  • 其次,app经过CPU完成对显示内容的计算,如:视图的建立、布局计算、图片解码、文本绘制等。在完成对现实内容的计算以后,app对图层进行打包,并在下一次RunLoop时将其发送至Render Server,即完成了一次commit Transaction操做。
  • Render Server主要执行OpenGL、Core Graphics相关程序,并调用GPU。
  • GPU则在物理层上完成了对图像的渲染。
  • 最终,GPU经过Frame Buffer、视频控制器等相关部件,将图像显示在屏幕上。

对上述步骤进行串联,他们执行所消耗的时间圆圆超过16.67ms,所以为了知足对屏幕的60FPS刷新率的支持,须要将这些步骤进行分解,经过流水线的方式并行执行,以下图:

Commit Transaction

Core Animation流水线中,app调用Render Server前的最后一步Commit Transaction其实能够细分为4个步骤:

  • Layout
  • Display
  • Prepare
  • Commit

Layout

Layout阶段主要进行视图构建,包括:LayoutSubviews方法的重载,addSubview:方法填充子视图等。

Display

Display阶段主要进行视图绘制,这里仅仅是设置成像的图元数据。重载视图的drawRect:方法能够自定义UIView的显示,其原理是在drawRect:方法内部绘制寄宿图,该过程使用GPU和内存。

Prepare

Prepare阶段属于附加步骤,通常处理图像的解码和转码等操做。

Commit

commit阶段主要将图层进行打包,并将它们发送至Render Server。该过程会递归执行,由于图层和视图都是以树形结构存在。

动画渲染原理

iOS动画的渲染也是基于上述Core Animation流水线完成的。这里咱们重点关注app与Render Server的执行流程。

平常开发中,若是不是特别的复杂动画,通常使用UIView Animation实现,iOS将其处理过程分为以下三部阶段:

  • Step1:调用animationWithDuration:animations:方法
  • Step2:在Animation Block中进行Layout,Display,Prepare,Commit等步骤。
  • Step3:Render Server根据Animation逐帧进行渲染。

参考博客 iOS图像渲染原理

相关文章
相关标签/搜索