14 419番外篇

上一篇文章只是大致翻译了一下419,如果仅仅是听他讲肯定还有很多我们不懂的地方,所以我需要用自己的语言重新去组织一下这个过程。

首先我们引出一个ios中的api叫做CADisplayLink,CADisplayLink是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器。我们在应用中创建一个新的CADisplayLink对象,把它添加到一个runloop中,并给它提供一个target和selector在屏幕刷新的时候调用。

注:通常来讲:iOS设备的刷新频率是60HZ也就是每秒60次。那么每一次刷新的时间就是1/60秒,大概16.7毫秒。

为什么会有这个api,因为屏幕成像的原理是,CRT 的电子枪按照上面方式,从上到下一行行扫描,扫描完成后显示器就呈现一帧画面,随后电子枪回到初始位置继续下一次扫描。为了把显示器的显示过程和系统的视频控制器进行同步,显示器(或者其他硬件)会用硬件时钟产生一系列的定时信号。当电子枪换到新的一行,准备进行扫描时,显示器会发出一个水平同步信号(horizonal synchronization),简称 HSync;而当一帧画面绘制完成后,电子枪回复到原位,准备画下一帧前,显示器会发出一个垂直同步信号(vertical synchronization),简称 VSync。显示器通常以固定频率进行刷新,这个刷新率就是 VSync 信号产生的频率。(具体过程可以看下面的连接,这里只做简单介绍)

知道了一些基本原理我们再来看看419


Core animation Pipeline

注:这里重新讲述一下Core Animation的概念,Core Animation其实是一个令人误解的命名。你可能认为它只是用来做动画的,但实际上它是从一个叫做Layer Kit这么一个不怎么和动画有关的名字演变而来,所以做动画这只是Core Animation特性的冰山一角。Core Animation是一个复合引擎,它的职责就是尽可能快地组合屏幕上不同的可视内容,这个内容是被分解成独立的图层,存储在一个叫做图层树的体系之中。于是这个树形成了UIKit以及在iOS应用程序当中你所能在屏幕上看见的一切的基础。实际上 Core Animation 框架做了很多基础工作:组合屏幕上的内容,追踪视图结构和内容的变化。

经过我们前面的科普之后,想必在座的同学就能对这个图片有个进阶的理解了,在每个Vsync的周期内,都可以接收一些事件进行处理。

首先大致讲一下左边箭头向下的过程,这些都是app内部发生的。

1.事件处理(比如触摸点击,以致需要引发界面修改),这发生在(commit transaction) 阶段,在这步过程的最后会将view hierarchy编码好并发送给render server。

2.render server这时候需要解码这个视图层次结构。render server必须等到下一次的显示缓存空出之后才可以发起GPU绘制操作,然后,开始调用绘制的操作API (openGL 或者metal API)。

3.在上述绘制资源准备好之后,GPU开始进行渲染,这个渲染过程最好在在下一次同步时间结束之前完成(16.67ms的刷新时间,以确保60帧的帧频)以便将frame buffer中的画面呈现给用户,并将缓存交给下次绘制。

注:流程图中 Commit Transaction 前面的红框代表触发视图内容变化的事件,比如点击按钮,之后Core Animation 框架会捕获到屏幕内容的变化并提交给 Render Server(渲染服务器),Render Server 里另外一个版本的 Core Animation 框架负责解码并绘制内容。

我们先从commit transaction开始,这是事物提交阶段。

在事务提交阶段有四个过程

1.layout: 建立(set up)views,会调用重载的layoutSubviews方法,这里会发生view的创建,以及通过addSubview将layers添加进view层级中,将内容聚集起来,并做一些轻量的数据库查找(因为不能在这里停留太久,轻量级的操作可以是本地化字符串的查找以供应label的layout。

2.display: 绘制views,这个阶段是如果drawRect有重载的话会通过drawRect绘制内容或者做字符串绘制,需要注意的是这个阶段实际上是CPU或者内存密集型的,这里我们用core graphics里的CGContext来渲染,能减少工作量和性能消耗。

3.prepare commit:做一些例如图像解码和图像转换的工作,图像解码很容易理解,如果有JPEG/PNG格式的图片,我们则需要对他们进行解码,如果有其他格式的图片,你可能要进行一些图片转换,一个好的解决方案是你可以把它们转换成bitmap来处理。

4.commit:打包layers并提交给render server,这个过程是递归的,所以需要确保view树的平整以确保高效。

再来看看动画的工作流程,动画有三个过程,前两个发生在应用内,第三个在render server。

1.是创建动画更新视图利用动画的方法。

2.跟上面的事物提交阶段类似,不同的是不仅仅提交视图层次结构,还提交动画。这样我们就能持续update你的动画而不用回去跟应用建立连接。

3.讲讲渲染之前,先科普一下渲染的概念。

渲染概念

这一节介绍了一些基本的渲染知识:屏幕被分割成 NxN 像素的小块来渲染,每个小块的大小与 SoC(System on Chip) 的cache相关。具体的操作过程如下:对于一个 app icon,被当做一个 CALayer 来渲染,而 CALayer 在 Core Animation 中被划分为两个三角形,每个三角形可以被继续分割成多个三角形,对每一个三角形单独渲染。这样做的目的是为了在每个时间点都可以获取每个tile中各像素集齐之后色彩总体的几何信息,并决定哪些像素可见,并决定运行哪个pixel shader,确保每像素只运行每个pixel shader一次。但如果需要做blending的话,就不止一次了,那么会有overdraw的问题。

注:图中的网格称之为tile bucket,块渲染 Tile Based Rendering。

块渲染是目前移动GPU的主流渲染方式,因为这种方式更好地适配了移动设备的耗电和性能的平衡问题。究其原因,是因为GPU在运算时对数据带宽消耗的极高要求:OPENGL的虚拟管线需要大量的显存带宽来支持, 为了减少这个凶残的带宽需求,大多数移动GPU都使用了tiled-based渲染。在最基础的层面,这些GPU将帧缓存(framebuffer),包括深度缓存,多采样缓存等等,从主内存移到了一块超高速的on-chip存储器上,计算芯片就能以远低于常规消耗的电能来读写存储器。但是on-chip的存储器都不可能很大,否则GPU芯片的大小将大的吓人,在有些GPU中小到只能容纳16x16个像素,于是将OPENGL的帧缓存切割成16x16的小块(这就是tile-based渲染的命名由来),然后一次就渲染一块。对于每一块tile: 将有用的几何体提交进去,当渲染完成时,将tile的数据拷贝回主内存。这样,带宽的消耗就只来自于写回主内存了,那是一个较小的消耗,消耗极高的深度/模板测试和颜色混合完全的在计算芯片上就完成了。

有关Tile Based Rendering的更多内容,有兴趣可以简单翻一下这篇译文《Performance Tunning for Tile-Based Architecture》

注:

着色器是可编程管线中的术语,其语法类似C语言,分为顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)。

Vertex shader – 在你的场景中,每个顶点都需要调用的程序,称为“顶点着色器”。假如你在渲染一个简单的场景:一个长方形,每个角只有一个顶点。于是vertex shader 会被调用四次。它负责执行:诸如灯光、几何变换等等的计算。得出最终的顶点位置后,为下面的片段着色器提供必须的数据。

Fragment shader – 在你的场景中,大概每个像素都会调用的程序,称为“片段着色器”。在一个简单的场景,也是刚刚说到的长方形。这个长方形所覆盖到的每一个像素,都会调用一次fragment shader。片段着色器的责任是计算灯光,以及更重要的是计算出每个像素的最终颜色。

渲染过程

渲染过程

这块详见参考资料7


参考资料

1. iOS 保持界面流畅的技巧

2. 第三章:iOS视图成像理论及优化

3. core animation pipeline

4. WWDC14_419_高级图形和动画

5.  iOS --- OpenGLES之着色器(shader)语法介绍

6. Tile-Based架构下的性能调校

7. iOS 2D Graphic(1)—— Concept 基本概念和原理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容