首页 > 系统 > iOS > 正文

iOS"离屏渲染"整理总结

2019-11-07 23:46:59
字体:
来源:转载
供稿:网友

一.渲染机制

CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示。

二.GPU屏幕渲染有两种方式

1>On-Screen Rendering:意为当前屏幕渲染

指GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行

2>Off-Screen Rendering:离屏渲染

指GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作

三.两种渲染方式比较

相比于当前屏幕渲染,离屏渲染的代价是很高的,主要体现在两个方面:

1>创建新缓冲区

要想进行离屏渲染,首先要创建一个新的缓冲区。

2>上下文切换

离屏渲染的整个过程,需要多次切换上下文环境:先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上有需要将上下文环境从离屏切换到当前屏幕。而上下文环境的切换是要付出很大代价的。

四.还有一种特殊的离屏渲染指:CPU渲染

如果重写了drawRect方法,并且使用任何Core Graphics的技术进行了绘制操作,就涉及到了CPU渲染。整个渲染过程由CPU在App内 同步地完成,渲染得到的bitmap最后再交由GPU用于显示。CoreGraphic通常是线程安全的,所以可以进行异步绘制,显示的时候再放回主线程,一个简单的异步绘制过程大致如下:

- (void)display { dispatch_async(backgroundQueue, ^{ CGContextRef ctx = CGBitmapContextCreate(...); // draw in context... CGImageRef img = CGBitmapContextCreateImage(ctx); CFRelease(ctx); dispatch_async(mainQueue, ^{ layer.contents = img; }); });}

五.离屏渲染的触发方式

⭐️shadows(阴影)

⭐️shouldRasterize(光栅化)

⭐️masks(遮罩)

⭐️edge antialiasing(抗锯齿)

⭐️group opacity(不透明)

⭐️复杂形状设置圆角等…

⭐️渐变

⭐️UILabel, CATextLayer, Core Text……


小插曲

日程经常打交道的TableViewCell,TableViewCell的重绘是很频繁的(因为Cell的复用),如果Cell的内容不断变化,则Cell需要不断重绘,如果此时设置了cell.layer可光栅化。则会造成大量的离屏渲染,降低图形性能。


值得注意的是,如果shouldRasterize被设置成YES,在触发离屏绘制的同时,会将光栅化后的内容缓存起来,如果对应的layer及其sublayers没有发生改变,在下一帧的时候可以直接复用。这将在很大程度上提升渲染性能

而其它属性如果是开启的,就不会有缓存,离屏绘制会在每一帧都发生。

六.为什么有时会使用离屏渲染

当使用圆角,阴影,遮罩的时候,图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制,所以就需要屏幕外渲染被唤起。屏幕外渲染并不意味着软件绘制,但是它意味着图层必须在被显示之前在一个屏幕外上下文中被渲染(不论CPU还是GPU).所以当使用离屏渲染的时候会很容易造成性能消耗,因为在OpenGL里离屏渲染会单独在内存中创建一个屏幕外缓冲区并进行渲染,而屏幕外缓冲区跟当前屏幕缓冲区上下文切换是很耗性能的。

七.Instruments工具检测

使用Instruments下的Core Animation有相关的检查选项

1>Color Offscreen-Rendered Yellow

开启后会把那些需要离屏渲染的图层高亮成黄色,这就意味着黄色图层可能存在性能问题。

2>Color Hits Green and Misses Red

如果shouldRasterize被设置成YES,对应的渲染结果会被缓存,如果图层是绿色,就表示这些缓存被复用;如果是红色就表示缓存会被重复创建,这就表示该处存在性能问题了。

八.该选择哪种实现方式?

1>尽量使用当前屏幕渲染

离屏渲染、CPU渲染可能带来的性能问题,一般情况下,我们要尽量使用当前屏幕渲染。

2>离屏渲染 和 CPU渲染

由于GPU的浮点运算能力比CPU强,CPU渲染的效率可能不如离屏渲染;但如果仅仅是实现一个简单的效果,直接使用CPU渲染的效率又可能比离屏渲染好,毕竟离屏渲染要涉及到缓冲区创建和上下文切换等耗时操作。

九.iOS系统版本区别

iOS 9.0 之前UIimageView跟UIButton设置圆角都会触发离屏渲染

iOS 9.0 之后UIButton设置圆角会触发离屏渲染,而UIImageView里png图片设置圆角不会触发离屏渲染了< iOS异步设置任意弧度高性能圆角图片>,如果设置其他阴影效果之类的还是会触发离屏渲染的。


参考学习以下博文

博文一(王中周) 博文二 博文三 博文四(全面)


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表