美文网首页
四、深入理解ios离屏渲染

四、深入理解ios离屏渲染

作者: 含笑州 | 来源:发表于2020-08-30 12:57 被阅读0次

我相信大多数做过iOS开发的都应该知道离屏渲染,也知道常见的造成离屏渲染的方式,但是对于它的原理可能了解的并不是很多,接下来我带大家了解一下。

一、了解离屏渲染

正常渲染流程如下:

图片来自网络

在正常情况下,经过CPU的计算以及GPU的渲染之后,会将结果存放到帧缓存区,随后视频控制器会读取帧缓存区的数据,经过数模转换,再逐行显示到屏幕上。

离屏渲染流程如下:图片来自网络

但是在有些情况下,系统会在屏幕以外开辟缓存区来存放一些中间状态的数据,等待全部的图层都渲染到离屏缓存区之后,分别从各个离屏缓存区取出数据,分别做相应的操作(裁剪等)之后,组合存入帧缓存区,再等待屏幕控制器的读取和屏幕刷新。

二、离屏渲染的利弊

1.劣势:

离屏渲染其实是加大了系统的负担,确实会造成性能上的损耗。主要表现在以下几个方面。

离屏渲染需要额外的存储空间,存储空间大小的上限是2.5倍的屏幕像素大小,一旦超过,则无法进行复用

离屏渲染缓存内容有时间限制,缓存内容100ms如果没有使用,那么它就会被丢弃,无法进行复用

容易掉帧:一旦因为离屏渲染导致最终存入帧缓存区的时候,超过了16.67ms,则会出现掉帧的情况

2.优势

虽然离屏渲染会需要多开辟出新的临时缓存区来存储中间状态,但是对于多次出现在屏幕上的数据,可以提前渲染好,从而达到复用的目的,这样CPU/GPU就不用做一些重复的计算。

其实在很多iOS开发的需求背景之下,比如 一些特殊动画效果的开发,此时需要多图层以及离屏缓存区保存中间状态,这种情况下就不得不使用离屏渲染

三、常见触发离屏渲染的几种方式:

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

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

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

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

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

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

在使用光栅化的时候,有以下建议:

1、如果layer不能被重用,则没必要使用光栅化;

2、如果我们更新已光栅化的layer,会造成大量的离屏渲染。例如UITableViewCell因为复用的原因,重绘是很频繁的。如果此时设置了光栅化,反而会造成大量离屏渲染,降低性能;

3、离屏渲染的缓存是有时间限制的,100ms内如果缓存的内容没有被复用,则会被丢弃,也就无法复用了;

4、离屏渲染的空间有限,超过2.5倍屏幕像素的大小,离屏渲染也会失效,无法复用

四、分析圆角触发离屏渲染案例

1.代码如下:

//1.按钮存在背景图片

    UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];

    btn1.frame=CGRectMake(100,30,100,100);

    btn1.layer.cornerRadius = 50;

[self.view addSubview:btn1];

    [btn1setImage:[UIImage imageNamed:@"btn.png"] forState:UIControlStateNormal];

btn1.clipsToBounds=YES;

    //2.按钮不存在背景图片

    UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom];

    btn2.frame=CGRectMake(100,180,100,100);

    btn2.layer.cornerRadius = 50;

    btn2.backgroundColor = [UIColor blueColor];

[self.view addSubview:btn2];

btn2.clipsToBounds=YES;

    //3.UIImageView 设置了图片+背景色;

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

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

    img1.backgroundColor = [UIColor blueColor];

[self.view addSubview:img1];

    img1.layer.cornerRadius = 50;

img1.layer.masksToBounds = YES;

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

    //4.UIImageView 只设置了图片,无背景色;

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

    img2.frame=CGRectMake(100,480,100,100);

[self.view addSubview:img2];

    img2.layer.cornerRadius = 50;

img2.layer.masksToBounds = YES;

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

我们可以发现上面的1和3会造成离屏渲染

五、如何检测离屏渲染呢

六、圆角导致的离屏渲染解决方案

方案一:

_imageView.clipsToBounds=YES;

_imageView.layer.cornerRadius=4.0;

方案二:

方案三:

方案四:

最后大家也可以参考下YYImage中对于圆角的处理代码:

- (UIImage *)yy_imageByRoundCornerRadius:(CGFloat)radius

 corners:(UIRectCorner)corners

 borderWidth:(CGFloat)borderWidth

 borderColor:(UIColor*)borderColor

 borderLineJoin:(CGLineJoin)borderLineJoin {

if (corners != UIRectCornerAllCorners) {

 UIRectCorner tmp = 0;

if (corners & UIRectCornerTopLeft) tmp |= UIRectCornerBottomLeft;

if (corners & UIRectCornerTopRight) tmp |= UIRectCornerBottomRight;

if (corners & UIRectCornerBottomLeft) tmp |= UIRectCornerTopLeft;

if (corners & UIRectCornerBottomRight) tmp |= UIRectCornerTopRight;

 corners = tmp;

 }

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

 CGContextRef context = UIGraphicsGetCurrentContext();

CGRectrect = CGRectMake(0,0,self.size.width,self.size.height);

 CGContextScaleCTM(context, 1, -1);

 CGContextTranslateCTM(context, 0, -rect.size.height);

CGFloatminSize =MIN(self.size.width,self.size.height);

if(borderWidth < minSize /2) {

 UIBezierPath*path = [UIBezierPathbezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth)byRoundingCorners:corners

cornerRadii:CGSizeMake(radius, borderWidth)];

 [pathclosePath];

 CGContextSaveGState(context);

 [pathaddClip];

CGContextDrawImage(context, rect,self.CGImage);

 CGContextRestoreGState(context);

 }

if(borderColor && borderWidth < minSize /2&& borderWidth >0) {

CGFloatstrokeInset = (floor(borderWidth *self.scale) +0.5) /self.scale;

 CGRectstrokeRect =CGRectInset(rect, strokeInset, strokeInset);

CGFloatstrokeRadius = radius >self.scale /2? radius -self.scale /2:0;

 UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadii:CGSizeMake(strokeRadius,

borderWidth)];

 [pathclosePath];

 path.lineWidth= borderWidth;

 path.lineJoinStyle= borderLineJoin;

 [borderColorsetStroke];

}

相关文章

  • iOS离屏渲染

    iOS-离屏渲染详解关于iOS离屏渲染的深入研究关于离屏渲染这两片文章分析的很详细。 渲染过程 根据渲染流水线示意...

  • iOS离屏渲染相关值得看的博客

    博客链接 iOS离屏渲染优化 绘制像素到屏幕上 关于iOS离屏渲染的深入研究 https://texturegro...

  • 四、深入理解ios离屏渲染

    我相信大多数做过iOS开发的都应该知道离屏渲染,也知道常见的造成离屏渲染的方式,但是对于它的原理可能了解的并不是很...

  • 关于 iOS离屏渲染的深入研究(进阶篇)

    关于 iOS离屏渲染的深入研究(进阶篇)

  • 待看文章

    内存相关 【基本功】深入剖析Swift性能优化 渲染相关 关于iOS离屏渲染的深入研究 线程相关 iOS-线程安全

  • 深入理解IOS离屏渲染

    目录:图像显示原理1.1 将图像显示到屏幕的流程1.2 显示器显示流程UI卡顿、掉帧2.1 屏幕撕裂 Screen...

  • 深入iOS离屏渲染

    相信许多iOS开发者,都听说过离屏渲染,大部分应该是面试的时候被问及。然而真正知道离屏渲染的原理的开发者并不很多。...

  • 离屏渲染

    非作者原著 来自摘抄 参考文献 iOS 关于离屏渲染的理解 以及解决方案 引起离屏渲染 为图层设置遮罩(layer...

  • iOS离屏渲染解析

    iOS离屏渲染解析

  • iOS圆角的离屏渲染,你真的弄明白了吗

    iOS圆角的离屏渲染,你真的弄明白了吗iOS圆角的离屏渲染,你真的弄明白了吗

网友评论

      本文标题:四、深入理解ios离屏渲染

      本文链接:https://www.haomeiwen.com/subject/wcqesktx.html