Advanced Graphics and Animations for iOS Apps

栏目: IOS · 发布时间: 5年前

内容简介:本文是对我们知道 Core Animation 是 iOS 上可用的图形渲染和动画基础结构,它将大部分实际绘图工作交给图形硬件以加速渲染。 我们先来看看 Core Animation 的管道图:

本文是对 Advanced Graphics and Animations for iOS Apps 的一个学习记录文章,字幕在 transcripts ,当然也可以下载 WWDC 在桌面上看带有字幕的视频。这篇挺实用的,讲解了渲染的基本流程,以及怎么发现并解决渲染性能的问题。

Core Animation Pipeline

我们知道 Core Animation 是 iOS 上可用的图形渲染和动画基础结构,它将大部分实际绘图工作交给图形硬件以加速渲染。 我们先来看看 Core Animation 的管道图:

Advanced Graphics and Animations for iOS Apps

我们看到在应用程序(Application)和渲染服务器(Render Server)中都有 Core Animation ,但是渲染工作并不是在应用程序里(尽管它有 Core Animation)完成的。它只是将视图层级(view hierarchy)打包(encode)提交给渲染服务器(一个单独的进程,也有 Core Animation), 视图层级才会被渲染。(“The view hierarchy is then rendered with Core Animation with OpenGL or metal, that’s the GPU.”) 大致流程如下:

  • Handle Events: 它代表 touch, 即一切要更新 视图层级 的事情;
  • Commit Transaction: 编码打包视图层级,发送给渲染服务器;
  • Decode: 渲染服务器第一件事就是解码这些视图层级;
  • Draw Calls: 渲染服务器必须等待下一次重新同步,以便等待缓冲区从 它们实现渲染的显示器 返回,然后最终开始为 GPU 绘制,这里就是 OpenGL or metal 。
  • Render: 一旦视图资源可用, GPU 就开始它的渲染工作,希望在下个重新同步完成,因为要交换缓冲区给用户。
  • Display: 显示给用户看。

在上述情况下,这些不同的步骤总共跨越三帧。在最后一个步骤 display 后,是可以平行操作的,在 Draw call 的时候可以处理下一个 handler event 和 Commit Transaction 。如下图所示

Advanced Graphics and Animations for iOS Apps

Commit Transaction

先聚焦 Commit transaction 这个阶段,因为这是开发者接触最多的,主要有四个阶段,如下图所示

Advanced Graphics and Animations for iOS Apps

layoutSubviews
drawRect:

Animation

动画分为三个阶段,前面两个阶段在应用程序,最后一个在渲染服务器,如下图所示

Advanced Graphics and Animations for iOS Apps

视图的不同的 是,这里提交的不是视图层级,而是动画。这是出于效率的原因,方便我们可以继续更新动画,而无需使用进程间通信来回复应用程序或强制它们返回应用程序。(因为如果提交视图层级的话,动画一更新,又得返回到应用程序提交新的视图层级,很耗时。)

Rendering Concepts

来了解渲染的一些概念。

Tile Based Rendering

“first tile based rendering is how all GPUs work.” 基于图块的渲染是 GPU 的工作方式。

Advanced Graphics and Animations for iOS Apps

  • 屏幕被分割成 N*N 个像素块,就像之前讲Points vs Pixels 中的例子一样;
  • 每块都适应 Soc 缓存。(Soc: 苹果 A9 是一款由苹果公司设计的系统芯片(Soc)。可以理解为系统芯片。 维基百科上面写的,这个芯片是 2015.9.9 才首次发布)。
  • 几何体被分割成瓷砖桶(tile buckets),这一步发生在 tiler stage (后面有提到)。这里举了 iPhone icon 的例子,从上图中可以看到,这个 icon 被分割成多个很小的三角形,使得这些三角形块可以单独的渲染,分割这样做的思路是可以决定哪一块显示,哪一块渲染。 因为每个像素只有一个像素着色器,所以混合的话还是有问题的,涉及到覆盖绘制。
  • 几何体提交后,光栅化才开始。(所以光栅化能提升性能,因为几何体都提交了,下次渲染的时候就可以省略这一步。)

Rendering pass

Advanced Graphics and Animations for iOS Apps

如上图所示,我们假设视图层级已经被提交到渲染服务器,并且 Core Animation 已经解码它,现在需要用 OpenGL 或者 metal 去渲染了,文章讲师举例是用的 OpenGL (所以这里的 Slide 比前面讲 Core Animation Pipeline 的 Slide 在 Render Server 这一栏,多了 OpenGL 在里面)。具体流程如下:

  • GPU 收到 Command Buffer ;
  • 顶点着色器开始运行,思路就是先将所有的顶点转换到屏幕空间,然后平铺处理,平铺成 瓷砖桶(tile bucket) 的几何图形(这里分两步走,先顶点处理后平铺,统称为 Tiler stage ,在 Instrument 的 OpenGL ES tiler utilization 能看到这一步。)这一步的产出被写入 Parameter Buffer, 下一阶段不会马上启动。相反,会等待,直到 a)处理完所有的几何体,并且位于 Parameter Buffer 或者 b) parameter buffer 已满(满了的话,必须刷新它)。
  • 像素着色器处理,这一步被称为 Renderer stage ,产出被写入 Render Buffer 。(在 Instrument 的 OpenGL ES renderer utilization 能看到这一步。)

Masking Rendering pass Example

举了一个渲染遮罩的例子,步骤如下图:

Advanced Graphics and Animations for iOS Apps

分三步走,两步渲染,一步合成。

  1. 将遮罩层(相机 icon)渲染到纹理(texture)上;
  2. 将内容层渲染到纹理上;
  3. 将遮罩添加到内容纹理上。

(texture: 材质贴图,又称纹理贴图,在计算机图形学中是把存储在内存里的位图包裹到 3D 渲染物体的表面。可以把它理解成图片。)

UIBlurEffect

UIBlurEffect 是 iOS8 新出的用来实现模糊效果的类。它的渲染过程如下:

Advanced Graphics and Animations for iOS Apps

再看下图,聚焦在一帧,

Advanced Graphics and Animations for iOS Apps

我们可以看到有三行,每一行代表一个事件

  • tile activity
  • render activity
  • VBlank interrupt, “and the last row I put in the VBlank interrupt and we can actually see what our frame boundaries are.” (我们实际上可以看到我们的帧边界是什么)

然后我们看看每个渲染步骤所需的时间,每个渲染步骤都牵扯到了上面所提到的事件(tile/render/VBlank interrupt)。

  1. content pass. 在这种情况下,它只是一个简单的图像,因此如果我们涉及 UI ,可能需要更长的时间;
  2. downscale, 它实际上相当快。这几乎是不变的成本;
  3. horizontal blur, 也非常快,因为是小区域。
  4. vertical blur, 同上
  5. upscale and tint the blur

我们注意到下图,每个步骤之间的间隙,用橘色标记了

Advanced Graphics and Animations for iOS Apps

5 个步骤中间有 4 个间隙,之所以存在,是因为这是发生在 GPU 上切换所花的时间。在空闲时间,每个步骤所花费的时间大概在 0.1~0.2ms, 所以总共 0.4~0.8ms, 所以这个是 16.67ms 的一个重要组成部分。(ps: 我们要减少这部分时间。)

还列举了不同设备间的耗时,有一种设备某个 Dark style 下的时间是 18.15ms, 超过 16.67ms, 所以不可能在 60 hert 渲染完成。所以 Apple 在这些设备上不支持 blur 。

UIBlurEffect 有三种 style: Extra light, Light, Dark ,它们消耗的资源各不相同, Dark 最少, Extra light 最多。

UIVibrancyEffect

UIVibrancyEffect 是在模糊之上使用的效果,它可以 确保内容突出,而不会被模糊 。它的渲染过程如下:

Advanced Graphics and Animations for iOS Apps

比 UIBlurEffect 多了两个步骤,最后一个步骤 filter 是最昂贵的,所以作用区域越小越好,千万别作用到全屏上。

Advanced Graphics and Animations for iOS Apps

所以也会比 UIBlurEffect 多两个间隙,所以总共 0.6~1.2ms.

Advanced Graphics and Animations for iOS Apps

Profiling tools

性能调查要考虑以下点

Advanced Graphics and Animations for iOS Apps

  • What is the frame rate? Goal is always 60 fps. // 检查工具: Core Animation template / OpenGL ES driver template
  • CPU or GPU bound? Lower utilization is desired and saves battery. (更少的 CPU 或者 GPU 利用率,让电池更持久。) // 检查工具: OpenGL ES driver template
  • Any unnecessary CPU rendering? GPU is desirable but know when CPU makes sense. (得知道渲染什么和怎么渲染, drawRect 方法尽量少用,让 GPU 做更多的渲染。) // 检查工具: Core Animation template / OpenGL ES driver template
  • Too many offscreen passes? Fewer is better. (前面说 UIBlurEffect 的时候有说到,橘色的间隙就是用在 GPU 切换时间,每个间隙大概 0.1~0.2ms 。 离屏渲染也会出现这样的情况,因为它必须进行切换,所以得减少。因为前面有提到,我们减少 CPU 或者 GPU 的使用时间。) // 检查工具: Core Animation template
  • Too much blending? less is better. (GPU 昂贵) // 检查工具: Core Animation template
  • Any strange image formats or sizes? Avoida on-the-fly conversions or resizing. (会转给 CPU 去处理,增加 CPU 的负担) // 检查工具: Core Animation template
  • Any expensive views or effects? Understand the cost of what is in use. (避免昂贵的效果,例如 Blur 和 Vibrancy ,得去评判。) // 检查工具: Xcode view debugging
  • Anything unexpected in the view hierarchy? Know the actual view hierarchy. (添加和移除要匹配。) // 检查工具: Xcode view debugging

检查工具

上面每个例子后面都有提到一个检测工具,这里来讲讲相应检测 工具 的作用。请注意一点,在开始挖掘代码以试图找出正在发生的事情之前,这总是一个很好的起点( 先看大概发生什么问题,再深入研究代码 )。

Core Animation template

  • 看 fps ;
  • color blended layers, green 表示不透明, red 代表需要去 blend 混合。 增加 GPU 的工作。 绿多红少,是理想中的状态。
  • color hit screens and misses red, 展示如何使用或滥用 CALayer’rasterize 属性,没命中缓存就是红色。第一次启动会有很多红色,因为必须在它被缓存之前渲染一次,后面就没有了,因为缓存了。
  • color copied images, 如果是 GPU 不支持的图片就会让 CPU 去转换(在 commit phase),增加了 CPU 的工作。 显示为蓝绿色(cyan)就表示让 CPU 去转换,影响滚动体验。 所以 size and color/image format 最好提前在后台处理好,不阻塞主线程。
  • color misaligned images, 黄色表示需要缩放,紫色表示像素没对齐。
  • color offscreen-rendered yellow, 黄色代表离屏渲染。 nav bar 和 tool bar 是黄色,因为这些图层的模糊实际上模糊了它背后的内容(前面 blur 有讲过)。
  • color OpenGL fast path blue, 蓝色是好事,由显示硬件去 blend ,这样就会减少 GPU 的工作。
  • flash updated regions, 正在更新的部分为黄色。 理想状况下,黄色区域越少越好。它意味着 CPU 和 GPU 的工作都减少了。

OpenGL ES driver template

  • device utilization, which will show you how much the GPU is in use during the trace. (时间越少越好 这里举例的是 30s vs 70s)
  • render and tiler utilization, correspond to the renderer and tiler phases.
  • CoreAnimationFramesPerSecond, what the actual frame rate is that we’re seeing.

Time Profiler template

  • 看调用栈耗时,看 CPU 在干什么;

Case studies

讲了两个例子(Fictitious Photo/Contacts Application),在旧设备上性能较差,都是 offscreen render 导致的,并且还是项目中常用的设置阴影和设置圆角。 要在不同的设备上测试,新设备没问题,可能旧设备就有问题。

Shadow

一般情况下是用以下代码,但是不要用

CALayer *imageViewLayer = cell.imageView.layer;
imageViewLayer.shadowColor = [UIColor blackColor].CGColor;
imageViewLayer.shadowOpacity = 1.0;
imageViewLayer.shadowRadius = 2.0;
imageViewLayer.shadowOffset = CGSizeMake(1.0, 1.0);

请用更高效的

imageViewLayer.shadowPath = CGPathCreateWithRect(imageRect, NULL);

因为 Core Animation 必须知道阴影的形状和位置,所以它用 offscreen pass 去渲染内容,在查看刚刚渲染的 alpha channel 来找出阴影的位置。

Round

一般情况下是用以下代码,但是不要用

CALayer *imageViewLayer = cell.imageView.layer;
imageViewLayer.cornerRadius = imageHeight / 2.0;
imageViewLayer.masksToBounds = YES;

下面的方式可能会更高效:

  • 不要在渲染的时候使用 mask ,提前生成圆头像
  • 如果上面的方式做不到,可以在头像上面盖一个中间透明的视图,尽管增加 GPU blend 的工作,但是还是会比离屏渲染快,所以还是可行的。

优化后设备利用率(Device Utilization)是 30% ,之前有 80% 没有达到 100% ,这是因为当有离屏渲染时, GPU 必须得有来回切换的空闲时间,所以我们知道尽管受到 GPU 的限制,由于 offscreen passes 的存在,都达不到 100% 。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java核心技术·卷1:基础知识(原书第9版)

Java核心技术·卷1:基础知识(原书第9版)

(美)Cay S. Horstmann、(美)Gary Cornell / 周立新、陈波、叶乃文、邝劲筠、杜永萍 / 机械工业出版社 / 2013-11-1 / 119.00

Java领域最有影响力和价值的著作之一,拥有20多年教学与研究经验的资深Java技术专家撰写(获Jolt大奖),与《Java编程思想》齐名,10余年全球畅销不衰,广受好评。第9版根据JavaSE7全面更新,同时修正了第8版中的不足,系统全面讲解Java语言的核心概念、语法、重要特性和开发方法,包含大量案例,实践性强。 《Java核心技术·卷1:基础知识》共14章。第1章概述了Java语言与其......一起来看看 《Java核心技术·卷1:基础知识(原书第9版)》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具