文章目录

  • 1. 屏幕显示图像的原理
  • 2. CPU在iOS中是如何工作的
  • 3. GPU在iOS中负责什么
  • 4. iOS中CPU和GPU的协同
  • 5. 在iOS中CPU的优化方向
  • 6. 在iOS中GPU的优化方向
  • 7. iOS中的离屏渲染
    • 7. 1. 离屏渲染是什么
    • 7. 2. CPU是否有离屏渲染概念?
    • 7. 3. GPU离屏渲染
    • 7. 4. iOS中离屏渲染场景
    • 7. 5. 离屏渲染的性能影响
    • 7. 6. 优化
      • 7.6.1 还有一些需要注意的点
    • 7. 7. 什么时候需要CPU渲染
      • 7. 7.1 需要注意的点
    • 7.8. 可以在项目进行的优化

1. 屏幕显示图像的原理

CRT 的电子枪按照从上到下一行行扫描,扫描完成后显示器就呈现一帧画面,随后电子枪回到初始位置继续下一次扫描。为了把显示器的显示过程和系统的视频控制器进行同步,显示器/屏幕设备(或者其他硬件)会用硬件时钟产生一系列的定时信号。当电子枪换到新的一行,准备进行扫描时,显示器会发出一个水平同步信号(horizonal synchronization),简称 HSync;而当一帧画面绘制完成后,电子枪回复到原位,准备画下一帧前,显示器会发出一个垂直同步信号(vertical synchronization),简称 VSync。显示器通常以固定频率进行刷新,这个刷新率就是 VSync 信号产生的频率。大致如下图所示

一般来说, CPU 计算好显示内容提交到 GPUGPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示。工作原理大致如下图

在最简单的情况下, 帧缓冲区只有一个,这时帧缓冲区的读取和刷新都都会有比较大的效率问题, 单一不能多线程处理。为了解决效率问题,显示系统通常会引入两个缓冲区,即双缓冲机制。在这种情况下,GPU 会预先渲染好一帧放入一个缓冲区内,让视频控制器读取,当下一帧渲染好后,GPU 会直接把视频控制器的指针指向第二个缓冲器。如此一来效率会有很大的提升。

双缓冲虽然能解决效率问题,但会引入一个新的问题。当视频控制器还未读取完成时,即屏幕内容刚显示一半时,GPU 将新的一帧内容提交到帧缓冲区并把两个缓冲区进行交换后,视频控制器就会把新的一帧数据的下半段显示到屏幕上,造成画面撕裂现象。如下图

为了解决这个问题,GPU 通常有一个机制叫做垂直同步(简写也是 V-Sync),当开启垂直同步后,GPU 会等待显示器的 VSync 信号发出后,才进行新的一帧渲染和缓冲区更新。这样能解决画面撕裂现象,也增加了画面流畅度,但需要消费更多的计算资源,也会带来部分延迟。

现在市场的状况, iOS 设备目前为止始终使用双缓存,并开启垂直同步。而安卓设备直到 4.1 版本,Google 才开始引入这种机制,目前安卓系统是三缓存+垂直同步。

2. CPU在iOS中是如何工作的

CPU: 中央处理器(central processing unit)作为智能设备系统的运算和控制核心,是信息处理、程序运行的最终执行单元.

在iOS中CPU做了哪些事情, 包括不仅限于对象的创建, 对象的调整, 对象的销毁, 布局计算, AutoLayou, 文本计算, 文本渲染, 图片解码, 图像绘制, 也就是说, 跟计算有关, 相关的CPU都有参与, 类似于人类的大脑, 至关重要, 虽然是多线程处理, 但是处理的事情多/事情复杂 就都会影响CPU的工作效率

3. GPU在iOS中负责什么

GPU: 图形处理器(英语:Graphics Processing Unit,缩写:GPU),又称显示核心、视觉处理器、显示芯片,是一种专门在个人电脑、工作站、游戏机和一些移动设备(如平板电脑、智能手机等)上做图像和图形相关运算工作的微处理器。

在iOS中GPU做了哪些事情, 纹理渲染, 视图混合, 图形的生成.

4. iOS中CPU和GPU的协同

首先请看图

众所周知iPhone显示器是 60帧/s 也就是 16.6666ms/帧 约等于 17ms

也就是说 T(cpu) + T(gpu) = 17ms 是最理想的状态 超过17ms就会产生卡顿, 也就是我们常说的掉帧.

所以优化的方向也是从这两方面入手, 减少CPU计算, 减少CPU的工作

5. 在iOS中CPU的优化方向

上面也提到了CPU都负责哪些工作, 优化也是从这些方面入手

  1. 对象创建, 用轻量的对象代替重量的对象, 比如CALayerUIView 要轻量许多
  2. 对象调整, UIView 的关于显示相关的属性(比如 frame/bounds/transform)等实际上都是 CALayer 属性映射来的,所以对 UIView 的这些属性进行调整时,消耗的资源要远大于一般的属性。对此你在应用中,应该尽量减少不必要的属性修改。当视图层次调整时,UIView、CALayer 之间会出现很多方法调用与通知,所以在优化性能时,应该尽量避免调整视图层次、添加和移除视图。(活用 hidden属性)
  3. 布局计算, 提前布局计算, 并进行缓存
  4. 文本计算, 用[NSAttributedString boundingRectWithSize:options:context:] 来计算文本宽高,用 -[NSAttributedString drawWithRect:options:context:]来绘制文本
  5. 图片的解码, 当你用 UIImageCGImageSource 的那几个方法创建图片时,图片数据并不会立刻解码。图片设置到 UIImageView 或者 CALayer.contents 中去,并且CALayer 被提交到 GPU 前,CGImage中的数据才会得到解码。这一步是发生在主线程的,并且不可避免。如果想要绕开这个机制,常见的做法是在后台线程先把图片绘制到 CGBitmapContext 中,然后从 Bitmap 直接创建图片。目前常见的网络图片库都自带这个功能。
  6. 图像的绘制, 图像的绘制通常是指用那些以 CG 开头的方法把图像绘制到画布中,然后从画布创建图片并显示这样一个过程。这个最常见的地方就是 [UIView drawRect:]里面了。由于 CoreGraphic方法通常都是线程安全的,所以图像的绘制可以很容易的放到后台线程进行。

6. 在iOS中GPU的优化方向

  1. 视图的混合, 当多个视图(或者说 CALayer)重叠在一起显示时,GPU会首先把他们混合到一起。如果视图结构过于复杂,混合的过程也会消耗很多 GPU资源。为了减轻这种情况的GPU消耗,应用应当尽量减少视图数量和层次,并在不透明的视图里标明 opaque属性以避免无用的 Alpha 通道合成。当然,这也可以用上面的方法,把多个视图预先渲染为一张图片来显示。

  2. 图形的生成, CALayerborder、圆角、阴影、遮罩(mask),CASharpLayer 的矢量图形显示,通常会触发离屏渲染(offscreen rendering),而离屏渲染通常发生在 GPU 中。当一个列表视图中出现大量圆角的 CALayer,并且快速滑动时,可以观察到 GPU 资源已经占满,而 CPU 资源消耗很少。这时界面仍然能正常滑动,但平均帧数会降到很低。为了避免这种情况,可以尝试开启 CALayer.shouldRasterize 属性,但这会把原本离屏渲染的操作转嫁到 CPU上去。对于只需要圆角的某些场合,也可以用一张已经绘制好的圆角图片覆盖到原本视图上面来模拟相同的视觉效果。最彻底的解决办法,就是把需要显示的图形在后台线程绘制为图片,避免使用圆角、阴影、遮罩等属性。

7. iOS中的离屏渲染

7. 1. 离屏渲染是什么

概念 : iOS App在渲染屏幕内容的时候 有一块与屏幕像素数据量一样大的frame buffer, 但是受当前屏幕渲染的局限因素限制, 而不得不在开辟一个空间(Offscreen Buffer)在做这件事, 这个过程叫做离屏渲染. 过程大致如下图

7. 2. CPU是否有离屏渲染概念?

根据苹果工程师的说法,CPU渲染并非真正意义上的离屏渲染。还有如果你的view实现了drawRect,此时打开Xcode调试的“Color offscreen rendered yellow”开关,你会发现这片区域不会被标记为黄色,说明Xcode并不认为这属于离屏渲染。

7. 3. GPU离屏渲染

GPU的渲染: 主要的渲染操作都是由CoreAnimationRender Server模块,通过调用显卡驱动所提供的OpenGL/Metal接口来执行的。通常对于每一层layerRender Server会按次序输出到frame buffer,后一层覆盖前一层,就能得到最终的显示结果, 但有些场景比较繁杂, 作为“画家”的GPU虽然可以一层一层往画布上进行输出,但是无法在某一层渲染完成之后,再回过头来擦除/改变其中的某个部分——因为在这一层之前的若干层layer像素数据,已经在渲染中被永久覆盖了。这就意味着,对于每一层layer,要么能找到一种通过单次遍历就能完成渲染的算法,要么就不得不另开一块内存,借助这个临时中转区域来完成一些更复杂的、多次的修改/剪裁操作

7. 4. iOS中离屏渲染场景

  • cornerRadius+clipsToBounds

  • shadow

  • group opacity: 将一对蓝色和红色layer叠在一起,然后在父layer上设置opacity=0.5,并复制一份在旁边作对比。左边关闭group opacity,右边保持默认(从iOS7开始,如果没有显式指定,group opacity会默认打开),然后打开offscreen rendering的调试,我们会发现右边的那一组确实是离屏渲染了

  • mask

  • UIBlurEffect

7. 5. 离屏渲染的性能影响

GPU的操作是高度流水线化的。本来所有计算工作都在有条不紊地正在向frame buffer输出,此时突然收到指令,需要输出到另一块内存,那么流水线中正在进行的一切都不得不被丢弃,切换到只能服务于我们当前的“切圆角”操作。等到完成以后再次清空,再回到向frame buffer输出的正常流程。

tableView或者collectionView中,滚动的每一帧变化都会触发每个cell的重新绘制,因此一旦存在离屏渲染,上面提到的上下文切换就会每秒发生60次,并且很可能每一帧有几十张的图片要求这么做,对于GPU的性能冲击可想而知(GPU非常擅长大规模并行计算,但是我想频繁的上下文切换显然不在其设计考量之中)

7. 6. 优化

以上可以看出, 有很多情况是无法避免的, 避免不了, 就尽量优化, 好在CALayer为这个方案提供了对应的解法:shouldRasterize。一旦被设置为true,Render Server就会强制把layer的渲染结果(包括其子layer,以及圆角、阴影、group opacity等等)保存在一块内存中,这样一来在下一帧仍然可以被复用,而不会再次触发离屏渲染。

layer.shouldRasterize = true;
7.6.1 还有一些需要注意的点
  • shouldRasterize的主旨在于降低性能损失,但总是至少会触发一次离屏渲染。如果你的layer本来并不复杂,也没有圆角阴影等等,打开这个开关反而会增加一次不必要的离屏渲染
  • 离屏渲染缓存有空间上限,最多不超过屏幕总像素的2.5倍大小
  • 一旦缓存超过100ms没有被使用,会自动被丢弃
  • layer的内容(包括子layer)必须是静态的,因为一旦发生变化(如resize,动画),之前辛苦处理得到的缓存就失效了。如果这件事频繁发生,我们就又回到了“每一帧都需要离屏渲染”的情景,而这正是开发者需要极力避免的。针对这种情况,Xcode提供了“Color Hits Green and Misses Red”的选项,帮助我们查看缓存的使用是否符合预期
  • 其实除了解决多次离屏渲染的开销,shouldRasterize在另一个场景中也可以使用:如果layer的子结构非常复杂,渲染一次所需时间较长,同样可以打开这个开关,把layer绘制到一块缓存,然后在接下来复用这个结果,这样就不需要每次都重新绘制整个layer树了

7. 7. 什么时候需要CPU渲染

其实渲染性能的调优, 就是在平衡CPU和GPU让他们尽量做各自最擅长的工作。

所以对于一些情况,如文字(CoreText使用CoreGraphics渲染)和图片(ImageIO)渲染,由于GPU并不擅长做这些工作,不得不先由CPU来处理好以后,再把结果作为texture传给GPU。除此以外,有时候也会遇到GPU实在忙不过来的情况,而CPU相对空闲(GPU瓶颈),这时可以让CPU分担一部分工作,提高整体效率。

7. 7.1 需要注意的点
  • 渲染不是CPU的强项,调用CoreGraphics会消耗其相当一部分计算时间,并且我们也不愿意因此阻塞用户操作,因此一般来说CPU渲染都在后台线程完成(这也是AsyncDisplayKit的主要思想),然后再回到主线程上,把渲染结果传回CoreAnimation。这样一来,多线程间数据同步会增加一定的复杂度
  • 同样因为CPU渲染速度不够快,因此只适合渲染静态的元素,如文字、图片(想象一下没有硬件加速的视频解码,性能惨不忍睹)
  • 作为渲染结果的bitmap(位图)数据量较大(形式上一般为解码后的UIImage),消耗内存较多,所以应该在使用完及时释放,并在需要的时候重新生成,否则很容易导致OOM(Out Of Memory)
  • 如果你选择使用CPU来做渲染,那么就没有理由再触发GPU的离屏渲染了,否则会同时存在两块内容相同的内存,而且CPU和GPU都会比较辛苦
  • 一定要使用Instruments的不同工具来测试性能,而不是仅凭猜测来做决定

7.8. 可以在项目进行的优化

  • 可以应用AsyncDisplayKit(Texture)作为主要渲染框架,对于文字和图片的异步渲染操作交由框架来处理。
  • 对于图片的圆角,预先使用CoreGraphics为图片裁剪圆角
  • 对于视频的圆角,由于实时剪切非常消耗性能,可以创建四个白色弧形的layer盖住四个角,从视觉上制造圆角的效果
  • 对于view的圆形边框,如果没有backgroundColor,可以放心使用cornerRadius来做
  • 对于所有的阴影,使用shadowPath来规避离屏渲染
  • 对于特殊形状的view,使用layer mask并打开shouldRasterize来对渲染结果进行缓存
  • 对于模糊效果,不采用系统提供的UIVisualEffect,而是另外实现模糊效果(CIGaussianBlur),并手动管理渲染结果

总结: 通过以上的阐述, 基本从CPU和GPU的角度做了一次, 深入的分析, 希望从这篇文章可以了解 影响界面流畅度的因素, 以及如何规避, 以及优化的方向, 归根结底其实就是, 平衡CPU和GPU, 以及减少两者的工作, 使其充分发挥其作用.

扩展阅读

Mastering Offscreen Render

iOS 保持界面流畅的技巧

关于iOS离屏渲染的深入研究

Getting Pixels onto the Screen

https://developer.apple.com/news/?id=gclaxoae

iOS 界面流畅度研究相关推荐

  1. Android性能优化——界面流畅度优化

    Android性能优化--界面流畅度优化 序言 首先流畅度不仅仅是受到代码的影响.也会跟机器的硬件配置有关系.所以第一点需要明确的是,流畅度最低保证在哪个硬件配置之上.这样有了一个基点之后,才能比较好 ...

  2. android5.1和ios差距,Android 5.1和IOS运行流畅度比较Android获胜!

    实践是检验真相的唯一标准,它一直是发布它的人们的教育,所以我一直认为Android不会比ios更加流畅,但是由于我吃了苹果,所以我有了改变了我以前的看法. 它是ip6p,系统是ios8.4,比较And ...

  3. ios android流畅度,流畅度如iOS!国内最流畅Android手机推荐

    原标题:流畅度如iOS!国内最流畅Android手机推荐 今天谷歌发布一款Android O(Anroid 8.0)简化版Android Go,这是专为低端手机设计的Android系统低配版,对硬件要 ...

  4. iOS 保持界面流畅的技巧,满满都是收获。

    前言 学如逆水行舟,不进则退.共勉!!! 这篇文章会非常详细的分析 iOS 界面构建中的各种性能问题以及对应的解决思路,同时给出一个开源的微博列表实现,通过实际的代码展示如何构建流畅的交互. 演示项目 ...

  5. android系统流畅度排行,最流畅安卓手机排名:华为mate40Pro第六,第一堪比iOS!...

    不可否认,苹果的iOS系统一直是手机行业的标杆,这些年安卓厂商们也在为追寻iOS的流畅度而努力,而随着120Hz屏幕刷新率等技术的普及之后,安卓手机在流畅度方面又上升了一级台阶. 日前,鲁大师发布了2 ...

  6. 华为鸿蒙运行是苹果几倍,鸿蒙2.0大战iOS,论流畅度苹果不是华为对手

    智能手机十多年的历史留下一个非常有意思的固有印象,很多人都以为安卓不如iOS流畅,特别是在机型的表现之上.一款新安卓手机用久了肯定会出现卡的问题,一般的iPhone机型是不会出现这样的问题的,所以我们 ...

  7. java一加到十_刘作虎“口出狂言”:一加7流畅度超过iphone,你相信吗?

    尽管是一个比较小众的手机品牌,一加一直受到不少网友的喜爱.和其他品牌不一样的是,一加手机一直坚持使用极其接近安卓原生态的深度系统,在界面上也更加的简洁.一加手机一直常年霸占了安卓手机的性能最强榜单,在 ...

  8. iphone13升级ios16好不好 流畅度有没有改变

    iOS16在本月如此发布了,而这次的iOS16在功能方面有很多改变,但用户们更关心的是它的流畅度如何,那么,iphone13升级ios16好不好? 流畅度有没有改变?下面就一起来看看吧. iphone ...

  9. 华为新系统鸿蒙效果,19款华为手机内测新系统,流畅度比肩苹果iOS,优先体验鸿蒙OS...

    原标题:19款华为手机内测新系统,流畅度比肩苹果iOS,优先体验鸿蒙OS 在前不久举办的HDC 2020大会上,华为新系统EMUI 11终于发布,10款老机型率先开启EMUI 11 Beta版内测,更 ...

最新文章

  1. ubuntu19 安装git_如何在Ubuntu 20.04上安装Git
  2. Linux实验二:vi编辑器的使用
  3. vue中 点击事件的写法_vue中的事件:原生事件与自定义事件__Vue.js
  4. 文件后缀可见的设置 强转文件类型
  5. 用matlab制作证件照,美图秀秀证件照制作方法图文教程
  6. ar9285网卡驱动 for linux,atheros ar9285无线网卡驱动 免费版
  7. 生鲜网超MySQL_天天生鲜项目实战-思路 数据库设计
  8. JDBC与MySQL练习
  9. ajax+php 实现即时聊天
  10. win10下如何安装win7自带的照片查看器。
  11. 如何准备国家公务员考试
  12. 【小程序】扫码预览时不显示图片
  13. 豆瓣十年,一个典型精英社区的起伏兴衰
  14. 电脑端播放m3u8视频
  15. CANoe操作介绍系列 ———— Analysi功能区中Graphic的介绍与使用
  16. Android 面试题中高级
  17. Kafka or RabbitMQ:消息中间件选型深入分析
  18. Lua Busted 单元测试简介(Windows 环境)
  19. 两分钟内教会你如何给视频加配音,快速掌握配音技巧!
  20. SpringBoot+Vue实现前后端分离的校园外卖配送系统

热门文章

  1. 高薪邀请国人去菲律宾上班的新型诈骗方式
  2. 全球及中国安防电源行业竞争状况及供需前景预测报告(新版)2022-2027
  3. 什么是4D(DRG、DLG、DOM、DEM)数据?(转自gisriver的空间)
  4. CCKS2020事理图谱应用工作:刘焕勇等.面向开放文本的逻辑推理知识抽取与事件影响推理探索
  5. 九日集训(每日打卡)第六天
  6. 写给互联网大厂员工的真心话,醍醐灌顶!
  7. Android手游外挂入侵----寓攻于守,方能破敌
  8. 使用C#编写一个读取和判断股票实时成交数据的小工具
  9. 压力测试Jmeter+badboy
  10. 加密网络空间安全厂商“观成科技”获数千万A轮融资,方广资本领投