美文网首页
iOS Rendering 四:Core Animation

iOS Rendering 四:Core Animation

作者: iOS_修心 | 来源:发表于2022-05-25 18:44 被阅读0次
    Core Animation Pipeline 渲染流水线
    1. Handle Events: 处理触摸事件,这个过程中有可能会需要改变页面的布局和界面层次。

    2. Commit Transaction:此时 app 会通过 CPU 处理显示内容的前置计算,比如布局计算、图片解码等任务,接下来会进行详细的讲解。之后将计算好的图层进行打包发给 Render Server。

    3. Decode:打包好的图层被传输到 Render Server 之后,首先会进行解码。注意完成解码之后需要等待下一个 RunLoop 才会执行下一步 Draw Calls。

    4. Draw Calls:解码完成后,Core Animation 会调用下层渲染框架(比如 OpenGL 或者 Metal)的方法进行绘制,进而调用到 GPU。

    5. Render:这一阶段主要由 GPU 进行渲染。

    6. Display:显示阶段,需要等 render 结束的下一个 RunLoop 触发显示。

    Commit Transaction 发生了什么

    一般开发当中能影响到的就是 Handle Events 和 Commit Transaction 这两个阶段,这也是开发者接触最多的部分。

    1. Layout:构建视图

    这个阶段主要处理视图的构建和布局,遍历的操作[UIView layerSubview][CALayer layoutSubLayers]

    • 调用重载的 layoutSubviews方法
    • 创建视图,并通过 addSubview方法添加子视图
    • 计算视图布局,即所有的 Layout Constraint

    由于这个阶段是在 CPU中进行,通常是 CPU 限制或者 IO 限制,所以我们应该尽量高效轻量地操作,减少这部分的时间,比如减少非必要的视图创建、简化布局计算、减少视图层级等。代码的主要调用结构如下:

    Layout调用伪代码
    1. Display:绘制视图

    这个阶段主要是交给 Core Graphics 进行视图的绘制,注意不是真正的显示,而是得到前文所说的图元 primitives 数据:

    根据UIView和CALayer的关系,我们知道,主要是CALayer来负责一个view的展示,并最终将得到的bitmap赋值给contents属性,保存在backing store中供后续使用。

    我们知道view的绘制会在drawRect:方法中,我们在其中打断点,可得到一下堆栈信息

    drawRect:绘制堆栈

    通过调用堆栈,可以得到此过程主要如下:

    1. 根据Layout获得的数据,进行展示
    2. 通过CALayer和UIView之间的代理来进行展示,主要实现在的display方法中
    • CALayer中实现[self drawInContext:context]: 传入上下文进行绘制

    • UIView中实现- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx:对界面进行绘制并传入上下文

    • UIView中实现- (void)displayLayer:(CALayer *)layer:通过UIGraphicsGetImageFromCurrentImageContext获取到当前上下文的图片,并赋值给layer.contents = (__bridge id)(image.CGImage);

    • 最后使用UIGraphicsEndImageContext关闭上下文

    1. 以上是默认的流程,如果自己重写实现了drawRect:,这个方法会直接调用 Core Graphics绘制方法得到bitmap数据,同时系统会额外申请一块内存,用于暂存绘制好的bitmap。这样绘制过程从 GPU转移到了CPU,这就导致了一定的效率损失。与此同时,这个过程会额外使用 CPU 和内存,因此需要高效绘制,否则容易造成 CPU 卡顿或者内存爆炸
    Display伪代码
    1. Prepare:Core Animation 额外的工作
    • 图片解码和转换
    1. Commit:打包并发送
    • 图层打包并发送到 Render Server

    注意: commit 操作是依赖图层树递归执行的,所以如果图层树过于复杂,commit 的开销就会很大。这也是我们希望减少视图层级,从而降低图层树复杂度的原因。

    Rendering Pass: Render Server 的具体操作

    Render Server 通常是OpenGL 或者是Metal。以 OpenGL 为例,那么上图主要是 GPU 中执行的操作,具体主要包括:

    1. GPU 收到 Command Buffer,包含图元 primitives 信息

    2. Tiler 开始工作:先通过顶点着色器 Vertex Shader 对顶点进行处理,更新图元信息

    3. 平铺过程:平铺生成 tile bucket 的几何图形,这一步会将图元信息转化为像素,之后将结果写入 Parameter Buffer 中

    4. Tiler 更新完所有的图元信息,或者 Parameter Buffer 已满,则会开始下一步

    5. Renderer 工作:将像素信息进行处理得到 bitmap,之后存入 Render Buffer

    6. Render Buffer 中存储有渲染好的 bitmap,供之后的 Display 操作使用

    使用 Instrument 的 OpenGL ES,可以对过程进行监控。OpenGL ES tiler utilization 和 OpenGL ES renderer utilization 可以分别监控 Tiler 和 Renderer 的工作情况

    动画渲染原理

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

    日常开发中,如果不是特别复杂的动画,一般使用 UIView Animation 实现,iOS 将其处理过程分为如下三部阶段:

    Step 1:调用 animationWithDuration:animations: 方法
    Step 2:在 Animation Block 中进行 Layout,Display,Prepare,Commit 等步骤。
    Step 3:Render Server 根据 Animation 逐帧进行渲染。

    相关文章

      网友评论

          本文标题:iOS Rendering 四:Core Animation

          本文链接:https://www.haomeiwen.com/subject/mvxyprtx.html