iOS离屏渲染

正常渲染与离屏渲染

iOS离屏渲染_第1张图片
image.png

正常渲染流程 :图像经过CPU解密后,由GPU渲染到帧缓冲区(FrameBuffer),然后扫描显示到屏幕上

  • GPU在渲染的过程中,遵循画家算法由远及近的顺序,依次将渲染结果放到帧缓冲区
  • 视频控制器从帧缓冲区读取一帧数据,显示到屏幕上后,帧缓冲区就会立即丢弃这帧数据,从而节省空间


    iOS离屏渲染_第2张图片
    正常渲染逻辑

离屏渲染流程:图像有CPU处理完成后,由GPU渲染到离屏缓冲区(OffscreenBuffer),在离屏缓冲区进一步处理合并后,提交到帧缓冲区,最后显示到屏幕上。

  • 当App需要额外的渲染和合并的时候,就会触发离屏渲染。例如UIButton切圆角,我们需要对button的所有图层进行圆角和剪裁,再讲合并后的结果存入帧缓冲区,再由帧缓冲区取出,显示到屏幕上,这时,正常的渲染流程,是无法做到对所有的图层进行圆角剪裁,因为它用一帧丢一帧。所以我们把处理的结果放到离屏缓冲区,讲几个图层叠加合并处理之后,放到帧缓冲区,最后显示到屏幕上。


    iOS离屏渲染_第3张图片
    离屏渲染的逻辑
圆角触发离屏渲染
    //1.按钮存在背景图片
    UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
    btn1.frame = CGRectMake(100, 30, 100, 100);
    btn1.layer.cornerRadius = 50;
    [self.view addSubview:btn1];
    
    [btn1 setImage:[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"];
iOS离屏渲染_第4张图片
Offscreen.png

当我们开启了masksToBounds或者clipsToBounds,同时还设置了图片,就会触发离屏渲染。其实不光是图片,我们为视图添加一个有颜色、内容或边框等有图像信息的子视图也会触发离屏渲染。

离屏渲染的另一个原因 - 光栅化shouldRasterize
iOS离屏渲染_第5张图片

开启光栅化,会将layer作为位图保存到离屏缓冲区,下次使用的时候,直接复用,提高渲染的效率
shouldRasterize光栅化的使用建议

  • 如果layer不能被复用,则没有必要开启光栅化
  • 如果layer不是静态的,需要被频繁修改,比如处于动画之中,那么开启光栅化反而影响了效率
  • 如果离屏缓存的内容有时间限制,缓存内容100ms内如果没有被使用,那么它就会被丢弃,无法进行复用
  • 离屏渲染的缓存空间有限,是屏幕的2.5倍,超过2.5倍屏幕像素大小的话也会失效,无法实现复用
离屏渲染对性能的影响
  • 离屏渲染进行了额外的渲染合并,有丢帧的可能
  • 离屏渲染的离屏缓冲区是额外开辟的空间,离屏缓冲区的空间并不是无限大的, 它是又上限的,最大只能是屏幕的2.5倍
既然离屏渲染有性能问题,为什么我们还要使用离屏渲染呢?
  • 特殊效果的处理并不能一次性完成,需要使用离屏缓冲区保存中间状态而不得不使用离屏渲染,这种情况是系统自动触发,例如圆角、音影、光栅化、毛玻璃等
  • 提高渲染效率 - 一个效果会多次出现,我们可以提前渲染保存到离屏缓冲区,达到复用的目的。 这是开发者手动触发的

ios如何检测离屏渲染

iOS离屏渲染_第6张图片
image.png

如上图,黄色的部分就是触发了离屏渲染。

离屏渲染触发原因总结

  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 等)

你可能感兴趣的:(iOS离屏渲染)