文档章节

iOS 离屏渲染

RainOrz
 RainOrz
发布于 2016/10/19 17:25
字数 1150
阅读 49
收藏 0

先放结论

  • 如果能够只用 cornerRadius 解决问题,就不用优化。

  • 如果必须设置 masksToBounds,可以参考圆角视图的数量,如果数量较少(一页只有几个)也可以考虑不用优化。

  • UIImageView 的圆角通过直接截取图片实现,其它视图的圆角可以通过 Core Graphics 画出圆角矩形实现。

GPU渲染机制:

CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示。

GPU屏幕渲染有以下两种方式:

  • On-Screen Rendering
    意为当前屏幕渲染,指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行。

  • Off-Screen Rendering
    意为离屏渲染,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。

离屏渲染的触发方式

设置了以下属性时,都会触发离屏绘制:

  • shouldRasterize(光栅化)
  • masks(遮罩)
  • shadows(阴影)
  • edge antialiasing(抗锯齿)
  • group opacity(不透明)
  • 复杂形状设置圆角等
  • 渐变

当使用圆角,阴影,遮罩的时候,图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制,所以就需要屏幕外渲染被唤起。

屏幕外渲染并不意味着软件绘制,但是它意味着图层必须在被显示之前在一个屏幕外上下文中被渲染(不论CPU还是GPU)。

所以当使用离屏渲染的时候会很容易造成性能消耗,因为在OPENGL里离屏渲染会单独在内存中创建一个屏幕外缓冲区并进行渲染,而屏幕外缓冲区跟当前屏幕缓冲区上下文切换是很耗性能的。

Instruments监测离屏渲染

Instruments的Core Animation工具中有几个和离屏渲染相关的检查选项:

  • Color Offscreen-Rendered Yellow
    开启后会把那些需要离屏渲染的图层高亮成黄色,这就意味着黄色图层可能存在性能问题。

  • Color Hits Green and Misses Red
    如果shouldRasterize被设置成YES,对应的渲染结果会被缓存,如果图层是绿色,就表示这些缓存被复用;如果是红色就表示缓存会被重复创建,这就表示该处存在性能问题了。

iOS版本上的优化

iOS 9.0 之前UIimageView跟UIButton设置圆角都会触发离屏渲染

iOS 9.0 之后UIButton设置圆角会触发离屏渲染,而UIImageView里png图片设置圆角不会触发离屏渲染了,如果设置其他阴影效果之类的还是会触发离屏渲染的。

这可能是苹果也意识到离屏渲染会产生性能问题,所以能不产生离屏渲染的地方苹果也就不用离屏渲染了。

正常添加:label.layer.cornerRadius = 8。但通常我们还会加上:label.layer.masksToBounds = true。此时并不会有性能损耗的,但是如是设置Color Offscreen-Rendered Yellow会发现 label 的四周出现了黄色的标记,说明这里出现了离屏渲染。

但是根据大神的测试,离屏渲染并非由设置圆角导致的,因为 UIView 只是设置了 cornerRadius,但它没有出现离屏渲染,设置 masksToBounds 会导致离屏渲染,从而影响性能,但是影响并没有想象中的那么大,例如有大神测试 17 个带有圆角的视图,滑动时的帧数依然在 58 - 59 fps 左右波动,甚至当屏幕上有奖金40个的时候,才开始有点卡顿,fps 下降到 33 左右,此时才会影响用户体验。

高效地设置圆角

普通的 UIView 设置圆角,和为 UIImageView 设置圆角的原理不同

override func drawRect(rect: CGRect) {
    let maskPath = UIBezierPath(roundedRect: rect,
                                byRoundingCorners: .AllCorners,
                                cornerRadii: CGSize(width: 3, height: 3))
    let maskLayer = CAShapeLayer()
    maskLayer.frame = self.bounds
    maskLayer.path = maskPath.CGPath
    self.layer.mask = maskLayer
}

此段代码可以实现 cornerRadius = 3 的效果,但是并不是完美的代码,但是实际测试中发现,对drawRect的重写会严重影响内存(内存暴增)和用户体验(更加卡顿),这种方法本质上是用遮罩层 mask 来实现,因此同样无可避免的会导致离屏渲染,但是带来的副作用是相比之前的fps在屏幕上圆角控件多的情况下,下降是原来的一倍!

© 著作权归作者所有

RainOrz
粉丝 8
博文 154
码字总数 95414
作品 0
青浦
程序员
私信 提问
2018 iOS 面试题大全(补充完整版)

原文地址:2018 iOS 面试题大全 由于原作者并没有继续更新,这里我转过来继续更新下 这个栏目将持续更新--请iOS的小伙伴关注! 1、iOS 应用导航模式有哪些? 2、iOS 中持久化方式有哪些? 3、...

Theendisthebegi
2018/11/15
0
0
iOS 7大量设计细节:黑色、白色,各种扁平设计

苹果将在下个月10号举行的WWDC 2013上推出下一代iOS和OS X,苹果iPhone、iPad和iPod touch将迎来界面大改的iOS 7。今天,据消息人士又给出了下一代iOS操作系统的设计细节。 苹果工业设计主管...

oschina
2013/05/25
4.7K
32
阿里云移动端播放器高级功能---画面控制

基本介绍 经常遇到一些开发者问: 1.我们播放的时候,会有黑边怎么处理?尤其是在类似于抖音,直播这样的场景下,如果视频有黑边,很影响画面的视觉效果。而阿里云播放器提供了缩放功能,用来...

阿里云云栖社区
03/05
0
0
GPU vs CPU in iOS

一直以来,我们做产品的时候并没有特别的去考虑CPU/GPU的使用,最近为了提升可视化功能的性能,发现合理使用GPU也是一个可以好好研究的部分,这里总结一下一些有用的信息。 中央处理器 CPU ...

雨_树
2018/07/10
0
0
iOS 10 发布:10 大新功能、预装 App 可删、信息更好玩

苹果在今天举行的 WWDC 发布会上,正式推出了 iOS 10。iOS 10 拥有10大新功能,系统的各个方面都得到了增强,信息应用功能更强大,更好玩。照片应用支持全新回忆功能,可以自动整理照片。Sir...

oschina
2016/06/14
4.2K
29

没有更多内容

加载失败,请刷新页面

加载更多

弹性盒模型常见例子

这篇文章主要是分享了三个例子( 垂直居中、响应式、圣杯 ),介绍了Flexbox的主要应用场景,并与传统方式对比, 感受Flexbox布局带来的便捷开发体验。 1 垂直居中对齐 不使用Flexbox <style>...

凌兮洛
13分钟前
0
0
Redis分布式锁服务

概述 在多线程环境下,通常会使用锁来保证有且只有一个线程来操作共享资源。比如: object obj = new object();lock (obj) { //操作共享资源 } 利用操作系统提供的锁机制,可以确保多线...

中关村的老男孩
18分钟前
1
0
idea+mybatis

报错信息如下 Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession.### The error may exist in com/bdqn/dao/UserDaoMappe......

冥焱
18分钟前
2
0
Android之用sharedUserId来实现不同应用(APK)数据共享

android:sharedUserId 当APK安装的时候,userid这个标志就会产生。APK在设备上的整个生命周期中,这个ID不再改变。不同设备上同一个应用包可能有不同的userid,重要的是在给定的设备上,每个...

天王盖地虎626
19分钟前
1
0
如何给龙芯电脑录屏

vokoscreen

gugudu
28分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部