offscreen rendering
如何检测你的项目中是否 触发了离屏渲染问题
那么为何有一些会触发离屏渲染,而有一些却不会触发呢?下面我们开始深入的探索。
离屏渲染的具体过程
我们知道通常的渲染流程是这样的:
app通过cpu和gpu的合作,不停的将内容渲染完成放入framebuffer帧缓存区,而屏幕显示不断从framebuffer中获取内容,显示实时的内容。
但是离屏渲染的流程是这样的:
在普通的情况下,gpu直接将渲染好的内容放入framebuffer中,但是在离屏渲染时不同,需要先额外创建离屏渲染缓存区offscreenbuffer。将提前渲染好的内容放入其中,等到合适的时机再将offsreebuffer中的内容进一步叠加、渲染。完成后将结果切换到framebuffer中。
离屏渲染的效率问题
从上面的流程来看,离屏渲染时,由于app需要提前对部分内容进行额外的渲染并保存到offscreenbuffer,以及需要在必要时对offscreenbuffer和framebuffer进行内容切换,所以会需要更长的处理时间。(实际上这两步切换的代价是非常大的)。
offscreenbuffer本身就需要额外的空间,大量的离屏渲染可能造成内存过大的压力。与此同时,offscreenbuffer的总大小也是有限的:不能超过屏幕总像素的2.5倍。
可见离屏渲染的开销非常大,一旦需要离屏渲染的内容过多,就容易造成掉帧问题,所以大部分情况下,我们要避免出现离屏渲染。
为什么要用离屏渲染
既然离屏渲染会造成性能问题,那么为什么还要使用离屏渲染?
其实主要是以下两种原因:
一些特殊的效果需要使用额外的offscreenbuffer来保存渲染中间的状态,所以不得不使用离屏渲染
出于效率的目的,可以将内容提前渲染并保存到offscreenbuffer中,从而达到复用的目的
例如,第一种原因,也就是不得不使用离屏渲染的情况。一般都是系统自动触发。如:阴影、圆角等。比如我们使用的蒙版(mask)功能,因为最终的结果是有超过一层的渲染结果进行叠加,所以必须要利用额外的内存空间对中间的渲染结果进行保存,因此系统会默认触发离屏渲染.
比如,ios8开始提供模糊特效uiblureffectview:
先渲染需要模糊的内容本身;
对内容进行缩放;
对上一步结果进行垂直模糊;
对上一步结果进行横向模糊;
最后一步,将模糊后的结果进行叠加合成,实现最终完整的模糊效果。
在这样的5次过程,系统也会自动触发离屏渲染,用来保存复杂的特效下,利用额外的内存空间对中间的结果进行保存,以便最后进行效果的合成。
离屏渲染的第二种原因:shouldrasterize 光栅化
开启光栅化后,就会主动触发离屏渲染。render server会强制将calayer渲染位图结果bitmap保存下来,这样下次渲染可以直接复用,提高效率;而保存下来的bitmap就已经包含了layer和sublayer、圆角、阴影、透明度等。
如果layer的构成包含了以上几种元素,结构非常复杂且还需要重复利用,可以考虑开启光栅化;因为layer 上的圆角、阴影、透明度等会由系统自动触发离屏渲染,那么打开光栅化就可以节约第二次以及以后的渲染时间。
而多层的sublayer的情况由于不会自动触发离屏渲染,所以相比之下会花费第一次离屏渲染的时间,但是可以节约后续重复的渲染开销。
使用光栅化的注意点:
如果layer并不能被复用,则没必要开启;
如果layer不是静态的,需要 被频繁修改,比如处于动画之中,那么开启离屏渲染反而影响效率了;
离屏渲染缓存内容有时间限制,缓存内容如果100ms没被复用,那么就会被丢弃,无法进行复用;
离屏渲染缓存空间有限,超过2.5倍屏幕像素大小的话,也会失效,且无法复用
圆角的离屏渲染探索
通常来讲,设置了layer的圆角效果后,会自动触发离屏渲染,但是具体什么情况下设置圆角才会触发离屏渲染?
如上图所示,layer由3层组成,我们设置圆角通常是用下面的代码:
view.layer.cornerradius = 2;
cornerradius - apple 官方介绍
根据苹果的描述,上面这句代码,只会默认设置backgroundcolor和border的圆角,而不会设置content的圆角,除非设置了layer.masktobounds为true(对应view的clicktobounds属性)。
如果只设置了cornerradius而没有设置maskstobounds,由于不需要叠加裁剪,此时是不会触发离屏渲染的。而当设置了裁剪属性时,由于masktobounds会对layer以及所有 的sublayer的content都进行裁剪,所以不得不触发离屏渲染。
view.layer.maskstobounds = true //触发离屏渲染的原因
离屏渲染的逻辑
刚才说圆角加上maskstobounds时,因为maskstobounds会对layer上的所有内容进行裁剪,从而诱发了离屏渲染,那么这个过程具体是怎么回事呢?我们来仔细研究一下:
在普通的layer绘制中,上层的sublayer会覆盖下层的sublayer,下层的sublayer在绘制完成后就可以抛弃了,从而节约空间提高效率。
所有sublayer一次绘制完毕后,整个绘制过程完成,就可以进行后续的呈现了。假设我们需要绘制一个三层的sublayer,并不设置裁剪和圆角,那么整个绘制过程就如下图所示:
绘制完进行display
设置了cornerradius以及maskstobounds
当我们设置了cornerradius以及maskstobounds进行圆角加裁剪时,maskstobounds裁剪属性会应用到所有的sublayer上,也就意味着所有的sublayer都要进行圆角+裁剪,意味着所有的sublayer在第一次绘制后,并不能立刻丢弃,而必须保存在offscreenbuffer中等待下一轮的圆角加裁剪操作,这样便引发了离屏渲染。
实际上,并不单只有圆角加裁剪会触发离屏渲染。如果设置了透明度和组透明(layer.allowsgroupopacity+layer.opacity),阴影属性(shadowoffset)等,都会产生这样的离屏渲染,因为这些都不是对单一的layer进行处理,而是对layer及其所有 的sublayer进行处理,从而引发离屏渲染。
避免圆角离屏渲染的手段:
除了尽量减少圆角裁剪的使用,还有什么别的办法可以避免圆角+裁剪引起的离屏渲染?
由于刚才提到,圆角引起离屏渲染的本质是裁剪的叠加,导致了maskstobounds对layer及其所有的sublayer进行了二次处理,那么我们只要避免使用maskstobounds进行二次处理,而是对所有的sublayer进行预处理,就可以只进行“画家算法(先绘制离屏幕较远的图层,然后绘制距离屏幕较近的图层,根据深度值,确定绘制顺序)”,用一次叠加就完成绘制。
有哪些可行方案
1.换资源
直接使用带圆角的图片,或者替换背景色为带圆角的纯色背景图,从而避免使用圆角裁剪。不过这周方法需要依赖具体情况,并不通用 。
2.mask
再增加一个和背景色相同的遮罩mask覆盖在最上层,盖住四个角,营造出圆角的形状。但这种方式难以解决背景色为图片 或渐变色的情况。注意这里的mask并不是指的layer上的mask,而是用两个view的叠加
3.uibezierpath
用贝塞尔曲线绘制闭合带圆角的矩形,在上下文设置只有内部可见,再将不带圆角的layer渲染成图片,添加到贝塞尔矩形中。这种方法效率较高,但是layer的布局一旦改变,贝塞尔曲线都需要手动进行重新绘制,所以需要对frame、color等进行手动监听并重绘。
4.coregraphics
重写 drawrect:,用coregraphics相关方法,在需要应用圆角时进行手动绘制。不过coregraphics效率也有限,如果多次调用也会有效率问题。
触发离屏渲染的几种情况
使用了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,coretext等)
举几个例子,加深下理解:
通过安装该Linux-HA软件可以实现Linux双机系统的高可用性解决方案
【世说芯品】解析旺盛的健康管理产品需求,兆易创新GD32如何帮助客户取胜?
基于VHDL和发接复用器的SDH系统设计及FPGA仿真
操作系统的概念和功能
存在感应技术选择要求与如何应用
如何检测你的项目中是否触发离屏渲染问题
南卡和万魔哪个好?佩戴舒适的蓝牙耳机推荐
酷睿i5-9500处理器上架 算是Intel压箱底的货了
大功率水冷光纤半导体激光电源ACDC恒压模块特点
旷视携手移动共创AI生态场景力 用AI点亮算网大脑
关于音频发烧友的两大门槛
河南首条智慧斑马线亮相 由LED发光地砖和立式信号灯箱组成
使用TensorFlow Model Analysis提升模型质量
5G+远程办公将为AR产业带来新的发展机遇
IBM Z 推出企业级 AI 新能力,持续助力主机客户 AI 之旅
目前毕业3年多,硬件工程师究竟如何发展?
硬核影音加BUFF, 东芝火箭炮Z670KF畅玩《最终幻想15》
关于Unix的历史和Linux的演化整理
国产激光雷达应用那些应用场景?
台式真空干燥箱DZF-6012的产品特点有哪些