iOS 离屏渲染
2020-07-10 本文已影响0人
阿木小丸子
1、什么是离屏渲染?
在正常情况下,经过CPU的计算以及GPU的渲染之后,会将结果存放到帧缓存区,随后视图控制器会读取帧缓存区的数据,经过数模转换,再逐行显示到屏幕上。
1.jpeg并且在GPU渲染的过程中,一般情况下,会遵循‘画家算法’按次序由远及近的一层一层将结果放置到帧缓存区中,当前帧缓存区的数据显示到屏幕上之后,就会将该帧丢弃,周而复始。
@图片来自网络.jpeg如果我们要对一个多图层的view设置圆角,当我们渲染完图层,要应用一些操作的时候,比如裁剪,之前放置在帧缓存区的数据早已经被丢弃,所以不能同时对多图层进行裁剪操作。
因此,我们需要开辟一些离屏缓存区来存放一些中间状态的数据,等待全部的图层都渲染到离屏缓存区之后,分别从各个离屏缓存区取出数据,分别做相应的操作(裁剪等)之后,组合存入帧缓存区,再等待屏幕控制器的读取和屏幕刷新。(参考HLinzl)
3.jpeg2、如何检测项目中哪些图层发生了离屏渲染?
我们先看如下的代码:
// 有图片
UIButton *btn1 = [[UIButton alloc]initWithFrame:CGRectMake(100, 40, 60, 60)];
[btn1 setImage:[UIImage imageNamed:@"test_icon"] forState:UIControlStateNormal];
btn1.layer.cornerRadius = 30;
btn1.clipsToBounds = YES;
[self.view addSubview:btn1];
// 无图片
UIButton *btn2 = [[UIButton alloc]initWithFrame:CGRectMake(100, 120, 60, 60)];
btn2.backgroundColor = [UIColor orangeColor];
btn2.layer.cornerRadius = 30;
btn2.clipsToBounds = YES;
[self.view addSubview:btn2];
// 有背景色 + 图片
UIImageView *imageV1 = [[UIImageView alloc]initWithFrame:CGRectMake(100, 200, 60, 60)];
imageV1.backgroundColor = [UIColor blueColor];
imageV1.image = [UIImage imageNamed:@"test_icon"];
imageV1.layer.cornerRadius = 30;
imageV1.layer.masksToBounds = YES;
[self.view addSubview:imageV1];
// 仅有图片
UIImageView *imageV2 = [[UIImageView alloc]initWithFrame:CGRectMake(100, 200, 60, 60)];
imageV2.image = [UIImage imageNamed:@"test_icon"];
imageV2.layer.cornerRadius = 30;
imageV2.layer.masksToBounds = YES;
[self.view addSubview:imageV2];
这写代码是我们平时做项目时会经常用到的,但是这些圆角的设置就一定会发生离屏渲染吗?
接下来,我们在模拟器运行这些代码,打开模拟器的如下设置:
设置.png看,神奇的现象就出现了!
运行结果.png上图的第一个和第三个就发生了离屏渲染
3、离屏渲染的利弊:
弊:
(1)离屏渲染需要额外开辟离屏缓冲区的存储空间,加大了系统的负担,会造成性能上的损耗。而存储空间的大小的上限是2.5倍的屏幕像素大小,一旦超过,则无法使用离屏渲染。
(2)一旦因为离屏渲染导致最终存入帧缓存区的时候已经超过了16.67ms,则会出现掉帧的情况。
利:
(1)在我们项目中有一些特殊的效果(比如一些特殊动画效果),需要额外的缓冲区来保存中间状态,不得不使用离屏渲染。
(2)如果某一个效果会多次出现在屏幕上,那么可以提前渲染offscreen Buffer ,来达到复用的目的,这样CPU/GPU就不用做一些重复的计算。
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 等)