美文网首页
离屏渲染浅析

离屏渲染浅析

作者: 源本平凡 | 来源:发表于2020-07-08 00:19 被阅读0次

1. 普通渲染

  • 正常情况下,渲染一张图片的流程:APP需要的渲染数据->CPU计算->GPU渲染->保存在帧缓存区(Frame Buffer)->视频控制器读取帧缓存区数据并显示在屏幕上。简要流程如下图所示:


    正常渲染流程.png
  • 在GPU的渲染过程中,显示到屏幕上的图像是遵循“画家算法”由远及近的顺序,依次将数据存储到帧缓存区。
  • 视频控制器从帧缓存区读取一帧数据,并将其显示到屏幕上之后,会立即抛弃这帧数据,不会做保留操作,这样做的目的是为了节约存储空间,也能保证每帧数据互不影响。

2. 离屏渲染

  • 与普通渲染不同,离屏渲染的流程:APP需要渲染的数据->CPU计算->GPU渲染->离屏渲染缓冲区(Offscreen Buffer)->保存在帧缓存区(Frame Buffer)->视频控制器读取帧缓存区数据并显示在屏幕上。简要流程如下图所示:


    离屏渲染流程.png

2.1 影响

  • 与非离屏渲染模式相比,多了进行额外的渲染合并操作,是对多个texture进行合并的过程。多了这么一步,所以说对性能要求更高一些,也更容易出现掉帧的情况。
  • 增加了额外的存储空间(离屏渲染缓冲区),其空间最大限制为屏幕像素的2.5倍

2.2 使用原因

情况1

  • 可以显示一些特殊效果,需要用到Offscreen buffer来保存中间状态。一般都是系统去触发,例如对layer层相关处理:包括圆角、阴影、mask等等。iOS系统扁平化后出现的高斯模糊也是利用离屏渲染方式。

圆角处理:

设置圆角为什么会触发离屏渲染呢?这个要从layer的结构说起。
layer结构中包含3部分:
backgroundColor
contents
boarder相关信息(borderWidth和borderColor)

设置圆角代码,这个大家应该都知道:

view.layer.cornerRadius = 1

我们先看看官方文档中cornerRadius相关说明:


cornerRadius.png

Discussion中的说明:
设置cornerRadius超过0.0,不会影响contents,但是会影响background color和border。如果设置了masksToBounds会对content进行裁剪。
所以说触发离屏渲染的主要原因:

masksToBounds=YES;

这就是模拟器开启离屏渲染模式中说明的为什么要设置masksToBounds的原因。masksToBounds需要对layer上的所有内容进行裁剪,过程中需要对中间值进行保存。所以进行了离屏渲染操作。
注意:
如果说layer图层比较简单,也是不会触发离屏渲染的。例如:UIImageView设置cornerRadius和masksToBounds是不会触发离屏渲染的,如果再对UIImageView设置背景色,则会触发。

    self.view.backgroundColor = [UIColor grayColor];
    
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];
    imageView.frame = CGRectMake(100, 100, 100, 100);
    imageView.layer.cornerRadius = 30;
    imageView.layer.masksToBounds = YES;
    [self.view addSubview:imageView];
    
    UIImageView *imageView2 = [[UIImageView alloc]  initWithImage:[UIImage imageNamed:@"1"]];
    imageView2.backgroundColor = UIColor.redColor;
    imageView2.frame = CGRectMake(100, 250, 100, 100);
    imageView2.layer.cornerRadius = 30;
    imageView2.layer.masksToBounds = YES;
    [self.view addSubview:imageView2];
    
    UIButton *btn = [UIButton   buttonWithType:UIButtonTypeCustom];
    [btn setBackgroundImage:[UIImage imageNamed:@"1"]   forState:UIControlStateNormal];
    btn.layer.cornerRadius = 30;
    btn.layer.masksToBounds = YES;
    btn.frame = CGRectMake(100, 400, 100, 100);
    [self.view addSubview:btn];

代码中有三个控件,前两个是UIImageView,最后一个是UIButton。

第一个UIImageView设置了图片没有设置背景色,没有触发离屏渲染。
第二个UIImageView设置了图片和背景色,触发了离屏渲染。
最后一个UIButton,设置图片没有设置背景色,触发了离屏渲染。原因是我们看到UIButton是由它的layer和UIImageView的layer混合起来的效果(UIButton有imageView),所以设置圆角的时候会触发离屏渲染。

情况2

  • 如果texture会多次显示到屏幕上,可以使用offscreen buffer进行提前渲染,并且保存在其中,达到复用的效果。layer中有shouldRasterize属性。这是一种主动行为,是为了提高复用的效率。通常是设置layer的shouldRasterize属性来实现。
    shouldRasterize 光栅化
    shouldRasterize官方文档
    shouldRasterize.png
    开启后,会将layer作为位图保存下来,下次直接与其他内容进行混合。这个保存的位置就是OffscreenBuffer中。这样下次需要再次渲染的时候,就可以直接拿来使用了。

shouldRasterize使用建议:

layer不复用,没必要使用shouldRasterize;
layer不是静态的,也就是说要频繁的进行修改,没必要使用shouldRasterize;
时间方面:离屏渲染缓存有100ms时间限制,超过该时间的内容会被丢弃,进而不能达到复用的目的;
空间方面:离屏渲染空间是屏幕像素的2.5倍,如果超过也无法复用。

2.3 如何避免

  • 为了避免设置圆角时引起的离屏渲染操作,可以用一下方案代替直接设置圆角的操作:
  1. 直接更换资源,让UI提供带圆角的图片。
  2. 使用layer.mask属性,增加一个和背景色相同的遮罩覆盖上层,盖住四个角,营造出圆角的形状。但这种方式难以解决背景色为图片或渐变色的情况。
  3. 使用贝塞尔曲线绘制闭合圆角的矩形,在上下文中设置只有内部可见,再将不带圆角的 layer 渲染成图片,添加到贝塞尔矩形中。这种方法效率更高,但是 layer 的布局一旦改变,贝塞尔曲线都需要手动地重新绘制,所以需要对 frame、color 等进行手动地监听并重绘。
  4. CoreGraphics重写 drawRect:,用 CoreGraphics 相关方法,在需要应用圆角时进行手动绘制。不过 CoreGraphics 效率也很有限,如果需要多次调用也会有效率问题。

2.4 产生原因总结

  • 设置layer.mashsToBounds/view.clipsToBounds
  • 设置layer.mask
  • 设置layer.shadow等相关属性
  • 设置layer.shouldRasterize光栅化
  • 设置了组透明度为 YES,并且透明度不为 1 的 layer (layer.allowsGroupOpacity/layer.opacity)
  • 绘制了文字的 layer (UILabel, CATextLayer, Core Text 等)

相关文章

  • 离屏渲染浅析

    GPU渲染机制: CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会...

  • 离屏渲染浅析

    1. 普通渲染 正常情况下,渲染一张图片的流程:APP需要的渲染数据->CPU计算->GPU渲染->保存在帧缓存区...

  • iOS--离屏渲染

    离屏渲染(Offscreen rendering) 离屏渲染的定义 离屏渲染(offscreen-renderin...

  • 图层性能-离屏渲染、光栅化等

    一.离屏渲染 1.在屏渲染、离屏渲染: On-Screen Rendering/在屏渲染:在屏渲染:指的是GPU的...

  • 关于离屏渲染

    1.什么是离屏渲染 2.离屏渲染的触发方式 3.离屏渲染的意义 4.离屏渲染的不足 1.什么是离屏渲染 要了解离屏...

  • 四、iOS离屏渲染

    一、开启图层是否触发离屏渲染问题 注:离屏渲染的图层会标记为黄色 二、离屏渲染的渲染流程 三、离屏渲染触发的原因 ...

  • UI视图及UITableView流畅性优化

    一.离屏渲染 1. 在屏渲染和离屏渲染 在屏渲染是指在当前用于显示的屏幕缓冲区进行GPU渲染操作 离屏渲染是指在当...

  • iOS下对离屏渲染的理解

    离屏渲染定义 离屏渲染的流程如图: GPU把渲染好的的内容存放到离屏渲染缓冲区中,在离屏渲染缓冲区(Offscre...

  • iOS渲染

    离屏渲染两种:CPU离屏渲染:1、使用 core graphics2、在 drawrect 中执行 GPU离屏渲染...

  • 003-iOS离屏渲染产生的原因

    离屏渲染产生的原因 在讨论离屏渲染之前我们先要搞清楚正常的渲染流程是怎样的 非离屏渲染流程: 我们可以看到在非离屏...

网友评论

      本文标题:离屏渲染浅析

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