iOS 离屏渲染的探究

2020/7/8 23:08:43

本文主要是介绍iOS 离屏渲染的探究,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

离屏渲染是在iOS开发面试中常见的一个问题,那么究竟什么是离屏渲染?什么情况下会触发离屏渲染?离屏渲染的有什么可取之处,又会造成什么问题?接下来我们借助几个例子来具体探讨一下。

1.什么是离屏渲染

我们知道iOS的系统中,非离屏渲染图层的显示,是经过CPU计算处理,通过GPU渲染,然后将渲染结果存放在帧缓存区中,然后才会被加载显示到屏幕上,大致流程如下:

普通渲染
但是,如果我们要显示的效果是,需要多图层叠加、裁剪、合并得到的最终效果时,也就是GPU需要将多次数据结合处理才可以得到一个最终要显示的效果,由于我们的帧缓存区的数据是放如一帧就会读取一帧显示,所以我们只能在最终要显示的结果放入帧缓存区,如果在此之前,需要多次处理渲染结果的叠加处理,我们就需要用到离屏渲染,也就是先将中间的渲染图层,存放在离屏缓存区,最后结合得到最终显示效果,再放入帧缓存区,其流程如下:

离屏渲染

2.什么情况下会触发离渲染

上面解释离什么是离屏渲染,那在开发中,什么场景会触发离屏渲染呢?有人说绘制圆角的时候会触发离屏渲染,但是这种说法是不准确的,实际上绘制圆角不一定会触发离屏渲染,我们通过代码验证这个问题,首先,将模拟器的离屏检查勾选上

2.1 圆角未触发离屏渲染

    UIView *view = [[UIView alloc]initWithFrame:CGRectMake(50, 50, 200, 200)];
    view.backgroundColor = [UIColor magentaColor];
    view.layer.borderColor = [UIColor cyanColor].CGColor;
    view.layer.cornerRadius = 100.0;
    view.layer.borderWidth = 5;
    // 设置背景和边框的裁剪
    view.clipsToBounds = YES;
    // 设置包括contents的边框裁剪
    view.layer.masksToBounds = YES;
    view.center = CGPointMake(self.view.center.x,view.center.y);
    [self.view addSubview:view];
    
    UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(50, 300, 200, 200)];
    imageView.image = [UIImage imageNamed:@"fff.jpg"];
    imageView.layer.cornerRadius = 100;
    // 设置背景和边框的裁剪
    imageView.clipsToBounds = YES;
    // 设置包括contents的边框裁剪
    imageView.layer.masksToBounds = YES;
    imageView.center = CGPointMake(self.view.center.x,imageView.center.y);
    [self.view addSubview:imageView];

复制代码

我们得到下面得运行结果,显然都没触发离屏渲染,这是因为我们代码中的view 和 imageView 都是一个图层就能完成的效果,也就是GPU只需要一次就能渲染完成,没有所谓的中间效果,直接得到来最终的显示效果,所以没有触发离屏渲染。

2.2 圆角触发离屏渲染

我们再来看下面这断代码

    UIView *view = [[UIView alloc]initWithFrame:CGRectMake(50, 50, 200, 200)];
    view.backgroundColor = [UIColor magentaColor];
    view.layer.borderColor = [UIColor cyanColor].CGColor;
    view.layer.cornerRadius = 100.0;
    view.layer.borderWidth = 5;
    //比上一段代码  多添加了contents
    view.layer.contents = (__bridge id )[UIImage imageNamed:@"fff.jpg"].CGImage;
    // 设置背景和边框的裁剪
    view.clipsToBounds = YES;
    // 设置包括contents的边框裁剪
    view.layer.masksToBounds = YES;
    view.center = CGPointMake(self.view.center.x,view.center.y);
    [self.view addSubview:view];
    
    UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(50, 300, 200, 200)];
    //比上一段多添加了背景颜色
    imageView.backgroundColor = [UIColor cyanColor];
    imageView.image = [UIImage imageNamed:@"fff.jpg"];
    imageView.layer.cornerRadius = 100;
    // 设置背景和边框的裁剪
    imageView.clipsToBounds = YES;
    // 设置包括contents的边框裁剪
    imageView.layer.masksToBounds = YES;
    imageView.center = CGPointMake(self.view.center.x,imageView.center.y);
    [self.view addSubview:imageView];
复制代码

而这次得到运行效果,view和imageView都触发了离屏渲染,下图就是运行效果

这里还是先上一张图,便于大家理解

图层
不管上面的view、还是imageView的最终显示效果都是下图显示的情况,我们的最终显示图层是由backgroundColor + 中间的contents + 边框 合并裁剪得到的结果,不是一次渲染能完成的结果,这时候,就需要将我们渲染的中间结果先存放在offScreen Buffer中,等所有的图层渲染完再合并得到最终结果,再放入帧缓存区,然后显示。这里需要注意,我们离屏缓冲区是有大小限制的,最大为屏幕的2.5陪像素值。

2.3 常见的会触发离屏渲染的情况

上面例子,我们知道触发离屏渲染的原因,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 等)

3.离屏渲染的优缺点

3.1 离屏渲染的缺点

我们知道,离屏渲染比普通的渲染,需要额外开辟空间,也就是离屏缓冲区,来存储和处理我们的中间渲染效果,这在性能上是造成来损耗的,主要表现在以下几个方面。 1.离屏渲染需要额外的存储空间,存储空间大小的上限是2.5倍的屏幕像素大小,一旦超过,则无法使用离屏渲染; 2.容易掉帧:一旦因为离屏渲染导致最终存入帧缓存区的时候,已经超过了16.67ms,则会出现掉帧的情况;

3.2离屏渲染的优点

虽然离屏渲染会造成性能损耗,但是在开发中遇到复杂的设计效果时,我们为来UI体验,还是要使用到离屏渲染,遇到复杂的、需要多次渲染才能得到显示效果时,我们可以利用离屏缓存区,提前将需要显示的图层渲染出来备用;重复利用的离屏渲染还可以复用,这样CPU/GPU就不用做一些重复的计算,但是注意把握还时间,离屏渲染的缓存是有时间限制的,100ms内如果缓存的内容没有被复用,则会被丢弃,也就无法复用了;



这篇关于iOS 离屏渲染的探究的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程