美文网首页
iOS离屏渲染

iOS离屏渲染

作者: 古方月 | 来源:发表于2020-07-21 17:58 被阅读0次

    正常渲染与离屏渲染

    image.png

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

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


      正常渲染逻辑

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

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


      离屏渲染的逻辑
    圆角触发离屏渲染
        //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"];
    
    Offscreen.png

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

    离屏渲染的另一个原因 - 光栅化shouldRasterize

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

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

    ios如何检测离屏渲染

    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离屏渲染

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