iOS的离屏渲染

图像显示原理(Off-Screen Rendering)

  1. CPU(Central Processing Unit,中央处理器)和GPU(Graphics Processing Unit,图形处理器)通过总线连接起来
  2. CPU往往输出结果的是位图。它负责对象的创建和销毁、对象属性的调整、布局计算、文本的计算和排版、图片的格式转换和解码、图像的绘制(Core Graphics等。
  3. CPU输出的位图信息在合适的时机上传到GPU,GPU拿到位图后进行图层的渲染,包括纹理的合成。之后会将处理结果放在帧缓冲区。
  4. 由视屏控制器根据垂直同步信号(VSync)在指定的时间之前,在帧缓冲区提取屏幕显示内容,然后将其显示到手机屏幕上。

卡顿产生等原因

  • CPU和GPU工作时所花时间过长,垂直同步信号过来的时候,计算和渲染还没有完成,导致掉帧
  • 卡顿解决的主要思路:尽可能减少CPU、GPU资源消耗

什么是离屏渲染

当我们在UIView上设置某些图层属性,比如设置视图的圆角属性、蒙层遮罩,标记未预合成之前,不能用于直接显示的时候,就触发了离屏渲染。离屏渲染的概念起源于GPU,指的是在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。
离屏渲染导致卡顿的原因:

  1. 需要创建新的缓冲区
  2. 离屏渲染的整个过程,需要多次切换上下文环境,先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上,又需要将上下文环境从离屏切换到当前屏幕
  3. 增加了GPU的工作量,可能导致GPU + CPU的耗时过多,在16.7毫秒(1秒60帧)的时候没有完成任务,出现卡顿掉帧。

如何检测是否触发离屏渲染?

WechatIMG422.png

打开模拟器运行,找到设置选项debug,勾选Color Off-screen Rendered,如果触发离屏渲染就会将控件标记为黄色。

什么操作会触发离屏渲染

圆角

  • 在iOS9之前,UIImageView同时设置layer.masksToBounds = YESlayer.cornerRadius大于0时就会触发离屏渲染,iOS 9之后系统做了优化,不会触发了。虽然系统做了优化,但是用这种方式给UIImageView圆角切割又设置了背景色,那么还是会触发离屏渲染的(普通UIView设置纯背景色不会)。
  • UIButtonmasksToBounds = YES下发生离屏渲染与背景图存不存在有关系, 如果没有给按钮设置 btn.image = [UIImage imageName:@"xxxxx"]; 是不会产生离屏渲染的。

如何解决呢?

  1. 让美工切图
  2. 通过CoreGraphics绘制裁剪圆角

不透明(group opacity)

GroupOpacity 是指 CALayerallowsGroupOpacity属性,UIView 的alpha属性等同于 CALayer opacity属性。开启 GroupOpacity 后,子 layer在视觉上的透明度的上限是其父layer 的opacity
GroupOpacity 开启离屏渲染的条件是:layer.opacity != 1.0并且有子 layer 或者背景图。

遮罩(mask)

  • mask生来会触发离屏渲染的。
  • mask是CALayer的一个属性,它也是一个CALayer对象,默认为nil。当给一个layer设置mask时,mask的alpha值决定了多少层背景跟内容通过并显示。当mask的alpha为0时,整个mask与底层CALayer都不会显示。当alpha为1时,只有mask区域以内非透明区域,会显示该区域对应底层CALayer的像素值。

阴影(shadow)

阴影直接合成在视图的下面,视图结构里并没有多出一个视图。在没有指定阴影路径时,阴影是沿着视图的非透明部分扩展的,而且 CALayer 的三个视觉元素至少有一个存在时才会有阴影。

使用阴影必须保证 layer 的masksToBounds = false,因此阴影与系统圆角不兼容。但是注意,只是在视觉上看不到,对性能的影响依然。通常这样实现一个阴影:

let imageViewLayer = avatorView.layer
imageViewLayer.shadowColor = UIColor.blackColor().CGColor
imageViewLayer.shadowOpacity = 1.0 //此参数默认为0,即阴影不显示
imageViewLayer.shadowRadius = 2.0 //给阴影加上圆角,对性能无明显影响
imageViewLayer.shadowOffset = CGSize(width: 5, height: 5)
//设定路径:与视图的边界相同
let path = UIBezierPath(rect: cell.imageView.bounds)
imageViewLayer.shadowPath = path.CGPath//路径默认为 nil

也就是说在设置阴影同时给layer设置相同的shadowPath,可避免离屏渲染。

光栅化(EdgeAntialiasing)

shouldRasterize(光栅化): 将图转化为一个个栅格组成的图象。 光栅化特点:每个元素对应帧缓冲区中的一像素。

shouldRasterize = YES在其它属性触发离屏渲染的同时,会将光栅化后的内容缓存起来,如果对应的layer或者 sublayers没有发生改变,在下一帧的时候可以直接复用,从而减少渲染的频率。
当使用光栅化是, 可以开启 "Color Hits Green and Misses Red"来检查该场景下是否适合选择光栅化,绿色表示缓存被复用,红色表示缓存在被重复创建.对于经常变动的内容,不要开启,否则会造成性能的浪费。

如果cell里面的内容不断变化(cell的复用),如果设置了cell.layer.shouldRaseterize = YES则会降低图形性能,造成离屏渲染.

参考链接

离屏渲染优化详解:实例示范+性能测试
iOS-离屏渲染详解

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