iOS离屏渲染相关探索

GPU屏幕渲染的方式有两种

  • On-Screen Rendering (当前屏幕渲染)
    GPU的渲染操作是在当前用于显示的屏幕缓冲区进行,不需要创建新的缓存,也不需要开启新的上下文,所以性能较好.但是会受到缓存大小限制等因素,一些复杂的操作无法完成.
  • Off-Screen Rendering(离屏渲染)
    GPU在当前屏幕缓冲区外开辟新的缓冲区进行操作
渲染流程对比.png

离屏渲染的过程分解

  1. 创建新的缓冲区(offScreenBuffer空间大小有限制,为屏幕像素点的2.5倍)
  2. 切换上下文到离屏缓冲区(消耗资源较大)
  3. 在离屏缓冲区进行渲染
  4. 切换上下文到显示屏幕上(消耗资源较大)
  5. 将离屏缓冲区的渲染结果显示到哦屏幕上

离屏渲染存在的问题

  1. Off-Screen Rendering空间大小有限制,为屏幕像素的2.5倍
  2. 容易掉帧,产生性能问题
  3. 渲染需要时间,会产生性能问题

离屏渲染的触发情况

  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 等)
针对光栅化的使用,有以下几个建议:
  • 如果layer不能被复用,则没有必要开启光栅化
  • 如果layer不是静态,需要被频繁修改(例如动画过程中),此时开启光栅化反而影响效率
  • 离屏渲染缓存内容有时间限制,如果100ms内没有被使用,那么就会丢弃,无法进行复用
  • 离屏渲染的缓存空间有限,是屏幕的2.5倍,超过2.5倍屏幕像素大小的话也会失效,无法实现复用

圆角中触发离屏渲染的时机

    //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"];
图四

从上面四个图可以发现图一和图三触发了离屏渲染,图二和图四没有,原因是为什么呢?

  • 首先来说一下CALayer的构成,它是由backgroundColor.content,borderColor和borderWith构成

    CALayer构成

  • 图一我们不设置btn2.clipsToBounds = YES;显示结果不是圆角

    Apple官方文档描述

  • 官放文档描述设置cornerRadius只会对backgroundColorborder生效,不会设置content圆角,将masksToBounds属性设置为YES将导致内容被剪切到圆角。

  • 所以圆角不生效的原因是没有对content设置圆角,UIButton设置image是放在content里面,所以按钮如果设置圆角必须要设置btn1.clipsToBounds = YES;/btn1.layer.masksToBounds = YES;才行.

  • 同理图三触发离屏渲染也是对CALayer进行了裁剪,图四圆角但是没有触发离屏渲染

  • 当content中有子视图,设置cornerRadiuslayer.masksToBounds /clipsToBounds就会触发离屏渲染,反之只设置backgroundColor/bordercontent中的一个,无论设置layer.masksToBounds /clipsToBounds是否等于YES都不会触发离屏渲染.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。