正常渲染与离屏渲染
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如上图,黄色的部分就是触发了离屏渲染。
离屏渲染触发原因总结
- 使用了 mask 的 layer (layer.mask)
- 需要进行裁剪的 layer (layer.masksToBounds / view.clipsToBounds)
- 设置了组透明度为 YES,并且透明度不为 1 的 layer (layer.allowsGroupOpacity/ layer.opacity)
- 添加了投影的 layer (layer.shadow*)
- 采用了光栅化的 layer (layer.shouldRasterize)
- 绘制了文字的 layer (UILabel, CATextLayer, Core Text 等)
网友评论