美文网首页
三、离屏渲染(OFFscreen Rendering)

三、离屏渲染(OFFscreen Rendering)

作者: A慢慢懂 | 来源:发表于2020-07-07 22:17 被阅读0次

1、离屏渲染流程

一般情况下,通常的渲染流程是这样的:


通常渲染流程.png

APP不停地将内容渲染完成保存Framebuffer帧缓冲区中,而显示屏幕不断滴从Framebuffer帧缓冲区获取内容。而离屏渲染则是这样的渲染流程:


离屏渲染流程.png
有此可见,离屏渲染是先将渲染内容保存到额外增加的离屏缓冲区,然后再将渲染内容不停滴保存到Framebuffer帧缓冲区中,再由屏幕读取渲染内容。

2、离屏渲染的性能问题

1.从上面流程上面来看,离屏渲染额外创建了离屏缓冲区,毫无疑问占用了内存空间,很有可能会出现内存压力过大的现象。并且呢,OffScreen buffer的总大小有限,不能超过屏幕总像素的2.5倍。
2.离屏渲染时需要APP提前对部分内容进行额外渲染并保存到离屏渲染缓冲区OffScreen buffer中,必要时需要再OffScreen buffer离屏渲染缓冲区和Frame Buffer帧缓冲区中进行内容切换,所以会需要更长的处理时间。

3、为什么使用离屏渲染呢

既然离屏渲染有性能问题,那为什么还要使用离屏渲染呢。
1、在实际开发中,会遇到一些特殊的效果,此时不得不用额外的Offscreen buffer 来保存渲染内容。
2、效率目的,可以将内容提前渲染保存到Offscreen buffer中,达到复用的目的。
针对第一种情况,我们常见的就是使用mask,比如阴影、圆角,这是系统自动触发的离屏渲染。比如 mask 蒙版

image.png
如图所示,由于最终的内容是由两层渲染结果叠加,所以必须要利用额外的内存空间对中间的渲染结果进行保存,因此系统会默认触发离屏渲染。
第二种情况使用的原因:shouldRasterize 光栅化

When the value of this property is YES, the layer is rendered as a bitmap in its local coordinate space and then composited to the destination with any other content.

开启光栅化后,会触发离屏渲染,Render Server 会强制将 CALayer 的渲染位图结果 bitmap 保存下来,这样下次再需要渲染时就可以直接复用,从而提高效率。
而保存的 bitmap 包含 layer 的 subLayer、圆角、阴影、组透明度 group opacity 等,所以如果 layer 的构成包含上述几种元素,结构复杂且需要反复利用,那么就可以考虑打开光栅化。
圆角、阴影、组透明度等会由系统自动触发离屏渲染,那么打开光栅化可以节约第二次及以后的渲染时间。而多层 subLayer 的情况由于不会自动触发离屏渲染,所以相比之下会多花费第一次离屏渲染的时间,但是可以节约后续的重复渲染的开销。
不过使用光栅化的时候需要注意以下几点:
1.如果 layer 不能被复用,则没有必要打开光栅化
2.如果 layer 不是静态,需要被频繁修改,比如处于动画之中,那么开启离屏渲染反而影响效率
3.离屏渲染缓存内容有时间限制,缓存内容 100ms 内如果没有被使用,那么就会被丢弃,无法进行复用
4.离屏渲染缓存空间有限,超过 2.5 倍屏幕像素大小的话也会失效,无法复用

圆角离屏渲染
是不是设置了圆角都会触发离屏渲染呢?不一定哟,圆角出发离屏渲染也是由条件的。
先打开模拟器的离屏渲染标记

渲染标记.png
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    //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"];
}
渲染图片.png
这四个例子都设置了圆角,但是只有第一个和第三个离屏渲染了,那是因为什么呢?
设置了layer.cornerRadius只会设置backgroundColor和border的圆角,不会设置content的圆角,除非同时设置了layer.masksToBounds(对应View中的clipsToBounds),layer.masksToBounds = true是触发离屏渲染的原因。第一个和第三例子图片内容的渲染和背景色渲染叠加,需要额外的Offscreen Buffer离屏渲染的来保存渲染叠加效果,所以是离屏渲染。第二个和第三个是只是单有背景颜色或者图片内容渲染,可直接用帧缓冲区即可,不会触发离屏渲染。
避免离屏渲染
1、尽量避免圆角裁剪的使用。
2、替换资源:直接使用有圆角的图片或者替换背景色为圆角的纯色背景,从而避免使用圆角裁剪。
3、使用mask再增加一个和背景色相同的遮罩 mask 覆盖在最上层,盖住四个角,营造出圆角的形状。但这种方式难以解决背景色为图片或渐变色的情况。
mask.png
4、UIBezierPath:用贝塞尔曲线绘制闭合带圆角的矩形,在上下文中设置只有内部可见,再将不带圆角的 layer 渲染成图片,添加到贝塞尔矩形中。这种方法效率更高,但是 layer 的布局一旦改变,贝塞尔曲线都需要手动地重新绘制,所以需要对 frame、color 等进行手动地监听并重绘。
5、CoreGraphics 重写 drawRect:,用 CoreGraphics 相关方法,在需要应用圆角时进行手动绘制。不过 CoreGraphics 效率也很有限,如果需要多次调用也会有效率问题。
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--离屏渲染

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

  • Offscreen Rendering

    Offscreen Rendering(离屏渲染)概念理解: 离屏渲染 是指系统为了绘制圆角(cornerRadi...

  • 003---离屛渲染

    Offscreen Rendering 离屏渲染 离屏渲染具体过程 通常的渲染流程是这样的: App 通过 CPU...

  • iOS中离屏渲染探索

    什么是离屏渲染? 离屏渲染(offscreen-rendering)顾名思义为屏幕外的渲染,即渲染的结果不会直接呈...

  • 离屏渲染触触发的问题

    离屏渲染的感念:离屏渲染(offscreen-rendering)顾名思义为屏幕外的渲染,即渲染的结果不会直接呈现...

  • 三、离屏渲染(OFFscreen Rendering)

    1、离屏渲染流程 一般情况下,通常的渲染流程是这样的: APP不停地将内容渲染完成保存Framebuffer帧缓冲...

  • 离屏渲染 Offscreen rendering

    Instruments 1、打开方式 2 触发方式 The biggest bottlenecks to grap...

  • 离屏渲染(OffScreen Rendering)

    一、基本概念 GPU屏幕渲染有两种方式 On-Screen Rendering 当前屏幕渲染,是指渲染操作是在当前...

  • 离屏渲染(Offscreen Rendering)

    直接将图层合成到帧的缓冲区中离屏渲染离屏渲染可以被 Core Animation 自动触发,或者被应用程序强制触发...

  • iOS 下离屏渲染的问题

    Offscreen Rendering 如何检测你的项目中是否 触发了离屏渲染问题 那么为何有一些会触发离屏渲染,...

网友评论

      本文标题:三、离屏渲染(OFFscreen Rendering)

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