iOS优化-离屏渲染

离屏渲染定义:

如果要在显示屏上显示内容,我们至少需要一块与屏幕像素数据量一样大的帧缓冲区(Frame Buffer),作为像素数据存储区域,而这也是GPU存储渲染结果的地方。

如果有时因为面临一些限制,无法把渲染结果直接写入frame buffer,而是先暂存在另外的内存区域(临时缓冲区),之后再写入frame buffer,那么这个过程被称之为离屏渲染。

离屏渲染的根本原因

视图包括多个图层, 在绘制过程中需要做混合图层的操作.

App在帧缓冲区之外开辟的一块临时缓冲区,用来进⾏额外的渲染和合并

最常用于他的优化:阴影+圆角+mask+cornerRadius+clipsToBounds+

直接使用CALayer的mask属性会导致离屏渲染

渲染性能的调优,其实始终是在做一件事:平衡CPUGPU的负载,让他们尽量做各自最擅长的工作。

触发离屏渲染的几种情况:

1、使用了mask的layer(layer.mask)

2、需要进行裁剪的layer(layer.maskToBounds/view.clipsToBounds)

3、设置了组透明度为YES,并且透明度不为1的layer(layer.allowsGroupOpacity/layer.opacity)

4、添加了投影的layer(layer.shodow*)

5、采用了光栅化的layer(layer.shouldRasterize)

6 、绘制了文字的layer(UILabel、CATextLayer、Core Text等)

如何优化:

1、使用AsyncDisplayKit(Texture);

2、图片:预处理-CoreGraphics/如果需要设置圆角,可以使用切好的圆角图片,或者自己使用贝塞尔曲线进行圆角绘制(最下面有代码)

3、视频圆角:图层盖住;

4、图片没有背景色->大胆使用cornerRadius

5、阴影shadowPath

6、凡是用mask遮罩,复用打开shouldRasterize,会进行复用

7、模糊效果(毛玻璃)不要用系统的,自定义


离屏渲染的利弊

优点:

(1)在我们项目中有一些特殊的效果(比如一些特殊动画效果),需要额外的缓冲区来保存中间状态,不得不使用离屏渲染。

(2)如果某一个效果会多次出现在屏幕上,那么可以提前渲染offscreen Buffer ,来达到复用的目的,这样CPU/GPU就不用做一些重复的计算。

提高渲染效率。比如说某种效果多次出现在屏幕上,利用离屏渲染机制进行复用。

缺点

(1)离屏渲染需要额外开辟离屏缓冲区的存储空间,加大了系统的负担,会造成性能上的损耗。而存储空间的大小的上限是2.5倍的屏幕像素大小,一旦超过,则无法使用离屏渲染。

(2)一旦因为离屏渲染导致最终存入帧缓存区的时候已经超过了16.67ms,则会出现掉帧的情况。

增大了性能的损耗。

容易掉帧。

离屏渲染的检测

可以通过在模拟器上,Debug-> Color Off-Screen Rendered

其中出现黄色背景的,则为触发了离屏渲染


肯定会触发的两种方式:毛玻璃效果,以及光栅化

// 触发方式1: 毛玻璃效果

    UIButton *btn0 = [UIButton buttonWithType:UIButtonTypeCustom];

    btn0.frame = CGRectMake(50, 30, 100, 100);

    [self.view addSubview:btn0];

    [btn0 setImage:[UIImage imageNamed:@"gdt_icon"] forState:UIControlStateNormal];

    UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

    UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];

    //必须给effcetView的frame赋值,因为UIVisualEffectView是一个加到UIIamgeView上的子视图.

    effectView.frame = CGRectMake(20, 20, 50, 50);

    [btn0 addSubview:effectView];

    // 触发方式2: shouldRasterize

    UIButton *btn_s = [UIButton buttonWithType:UIButtonTypeCustom];

    btn_s.frame = CGRectMake(200, 30, 100, 100);

    btn_s.layer.shouldRasterize = YES;

    [self.view addSubview:btn_s];

    [btn_s setImage:[UIImage imageNamed:@"gdt_icon"] forState:UIControlStateNormal];

Button和ImageView的情况


Button和ImageView的情况

//1、Button存在背景图片

    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];

    btn.frame=CGRectMake(50,120,100,50);

    [btnsetImage:[UIImage imageNamed:@"offscreen.png"] forState:UIControlStateNormal];

    btn.backgroundColor = UIColor.blueColor;

    //btn.layer.cornerRadius = 20;//有离屏渲染

    btn.imageView.layer.cornerRadius = 20;//无离屏渲染

    btn.clipsToBounds = YES;

    [self.view addSubview:btn];


    //2、Button不存在背景图片//无离屏渲染

    UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];

    btn1.frame=CGRectMake(200,120,100,50);

    btn1.backgroundColor = UIColor.blueColor;

    btn1.layer.cornerRadius = 20;

    btn1.clipsToBounds=YES;

    [self.viewaddSubview:btn1];


    //UIImageView 设置了图片+背景色; //有离屏渲染

    UIImageView *img1 = [[UIImageView alloc]init];

    img1.frame=CGRectMake(50,320,100,100);

    img1.backgroundColor = [UIColor blueColor];

    img1.layer.cornerRadius = 50;

    img1.layer.masksToBounds = YES;

    img1.image = [UIImage imageNamed:@"offscreen.png"];

    [self.viewaddSubview:img1];


    //UIImageView 只设置了图片,无背景色; //无离屏渲染

    UIImageView *img2 = [[UIImageView alloc]init];

    img2.frame=CGRectMake(200,320,100,100);

    img2.layer.cornerRadius = 50;

    img2.layer.masksToBounds = YES;

    img2.image = [UIImage imageNamed:@"offscreen.png"];

    [self.view addSubview:img2];

其他开发者的优化:

即刻大量应用AsyncDisplayKit(Texture)作为主要渲染框架,对于文字和图片的异步渲染操作交由框架来处理。关于这方面可以看我之前的一些介绍

对于图片的圆角,统一采用“precomposite”的策略,也就是不经由容器来做剪切,而是预先使用CoreGraphics为图片裁剪圆角

对于视频的圆角,由于实时剪切非常消耗性能,我们会创建四个白色弧形的layer盖住四个角,从视觉上制造圆角的效果

对于view的圆形边框,如果没有backgroundColor,可以放心使用cornerRadius来做

对于所有的阴影,使用shadowPath来规避离屏渲染

对于特殊形状的view,使用layer mask并打开shouldRasterize来对渲染结果进行缓存

对于模糊效果,不采用系统提供的UIVisualEffect,而是另外实现模糊效果(CIGaussianBlur),并手动管理渲染结果

UIBezierPath是UIKit中Core Graphics框架中的一个类,使用UIBezierPath可以绘制各种简单的图形。

在这里绘制贝塞尔曲线:- (void)drawRect:(CGRect)rect

重新绘制:调用- (void)drawRect:(CGRect)rect或者专门的方法[self setNeedsDisplay];

CAShapeLayer和drawRect比较:

CAShapeLayer:属于CoreAnimation框架,通过GPU来渲染图形,不耗费性能。

drawRect:属于Core Graphics框架爱,占用大量CPU,耗费性能。

怎么高效的实现控件的圆角效果?第八条

//直接对图片进行重绘 (使用Core Graphics),实际开发加异步处理,也可以给 SDWebImage 也做扩展;

- (UIImage *)imageWithCornerRadius:(CGFloat)radius {

   CGRect rect = (CGRect){0.f,0.f,self.size};

   UIGraphicsBeginImageContextWithOptions(self.size,NO, UIScreen.mainScreen.scale);

   CGContextAddPath(UIGraphicsGetCurrentContext(), [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius].CGPath);

   CGContextClip(UIGraphicsGetCurrentContext());

   [selfdrawInRect:rect];

   UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

   UIGraphicsEndImageContext();

   returnimage;

}

// 利用CAShapeLayer圆角,替换原本的layer,达到圆角效果

UIBezierPath*maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:self.bounds.size];

CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];

maskLayer.frame =self.bounds;

maskLayer.path = maskPath.CGPath;

self.layer.mask = maskLayer;


参考:https://juejin.cn/post/6847902220017467406

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

推荐阅读更多精彩内容

  • 前言 本篇文章是摘录,为了纪录学习,文中讲了什么是离屏渲染,以及开发中,出现礼品渲染的几种情况,以及如何最大程度的...
    天下林子阅读 1,474评论 2 6
  • 我们经常遇到有关离屏渲染(Offscreen rendering) 的知识点。一般来说,绝大多数人都能够回答出“圆...
    红粉青娥映楚云阅读 348评论 0 2
  • 在平时的iOS面试中,我们经常会考察有关离屏渲染(Offscreen rendering)的知识点。一般来说,绝大...
    Dayon阅读 931评论 0 1
  •   上一篇 我们介绍了图像从数据到屏幕的渲染过程,现在我们来研究一下iOS的离屏渲染。那我们先来看一下渲染模式,i...
    卡卡奇布阅读 1,739评论 0 4
  • 1.iOS界面渲染过程 1.在Application这一层中主要是CPU在操作,而到了Render Server这...
    wu890608阅读 323评论 0 3