当前屏幕渲染不需要额外创立新的缓存,为了让呈现器的呈现跟视频控制器同步

当前屏幕渲染不需要额外创建新的缓存,为了让显示器的显示跟视频控制器同步

移步接纳优化到最终关键仍然看FPS(页面流畅程度)性能、内存占用等地点。离屏渲染也是老生常谈的一个问题,本文侧重点在广泛导致离屏渲染的因素及缓解方案。

屏幕呈现图像的原理:

这就是说为何离屏渲染会引起性能问题?

OpenGL中,GPU屏幕渲染有二种方法: On-Screen Rendering (当前屏幕渲染)
Off-Screen Rendering (离屏渲染)
,当前屏幕渲染不需要额外创立新的缓存,也不需要打开新的上下文,相对于离屏渲染性能更好。可是受当前屏幕渲染的受制因素限制(只有自己上下文、屏幕缓存有限等),当前屏幕渲染有些境况下的渲染解决不了的,就利用到离屏渲染。离屏渲染的整个经过需要切换上下文环境,先从
当前屏幕切换来离屏,等收尾后,又要将上下文环境切换回来.这也是怎么会消耗性能的原由了。

离屏渲染引发因素有
cornerRadius(设置圆角)、shadows(阴影)、masks(遮罩)、edge
antialiasing(抗锯齿)、group
opacity(不透明)、shouldRasterize(光栅化)

等,至于检测离屏渲染的工具 Instruments的Core Animation
就不多说了。本文重要介绍 设置圆角阴影 的方案。

高中物理应该学过展现器是怎样显示图像的:需要出示的图像经过CRT电子枪以极快的速度一行一行的围观,扫描出来就展现了一帧画面,随后电子枪又会重临先河地点循环扫描,形成了大家看到的图片或视频。

设置圆角

正常做法:

   //只需要设置layer层的两个属性
   //设置圆角
   imageView.layer.cornerRadius = imageView.frame.size.width / 2;
   //将多余的部分切掉
   imageView.layer.masksToBounds = YES;

此处提供三种避免离屏渲染的方案

  • 1.视图上添加一个子layer到最上层,用于覆盖该视图及其子视图,设置layer的图纸为刚刚可以遮盖成所需圆角样子,并且图片颜色刚好是该视图父视图的背景颜色就达成想要的效率。
    原文地址
    ,该作者写的很好,封装了一个UIView的分类,3个API,分别是
    安装一个四角圆角,设置一个指定地方的圆角,设置一个带边框的圆角

    github地址

/**
 设置一个四角圆角

 @param radius 圆角半径
 @param color  圆角背景色
 */
- (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color;

/**
 设置一个普通圆角

 @param radius  圆角半径
 @param color   圆角背景色
 @param corners 圆角位置
 */
- (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color corners:(UIRectCorner)corners;

/**
 设置一个带边框的圆角

 @param cornerRadii 圆角半径cornerRadii
 @param color       圆角背景色
 @param corners     圆角位置
 @param borderColor 边框颜色
 @param borderWidth 边框线宽
 */
- (void)xw_roundedCornerWithCornerRadii:(CGSize)cornerRadii cornerColor:(UIColor *)color corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;

下载下来那些分类直接拖入工程就可以选拔了,调用很有利,然则使用的时候会发现,这六个API都急需传一个参数
cornerColor (父视图的背景观),所以也促成了这些成效的受制,即
设若该父视图的颜料不是纯色,此时该措施就不适用了,同样
假定父视图的颜色会变化,这实现起来的代码也不那么优雅,如下图,有点窘迫,这里引出了第二种方案。

边角颜色与背景观不符

  • 2.由此修改layer.mask,首先通过贝塞尔曲线创立基于矢量的门道
    ,传递给CAShapeLayer举办渲染。路径闭环,再把绘制出的Shape赋值给layer.mask,在Mask范围之外的Layer将不被出示从而达成圆角功效。代码实现很简单,如下:

    UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(130, 330, 100, 100)];
    [btn setBackgroundColor:[UIColor colorWithRed:(226.0 / 255.0) green:(113.0 / 255.0) blue:(19.0 / 255.0) alpha:1]];
    [backgroundImageView addSubview:btn];
    //绘制曲线路径
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:btn.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:btn.bounds.size];
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
    //设置大小
    maskLayer.frame = btn.bounds;
    //设置图形样子
    maskLayer.path = maskPath.CGPath;
    btn.layer.mask = maskLayer;

效果图:

民用认为第二种方案更简短而且效率扩充性更强些

为了让呈现器的显示跟视频控制器同步,当电子枪新扫描一行的时候,准备扫描的时发送一个程度同步信号(HSync信号),展现器的基础代谢频率就是HSync信号爆发的效用。然后CPU总括好frame等属性,将总括好的始末提交GPU去渲染,GPU渲染好之后就会放入帧缓冲区。然后视频控制器会按照HSync信号逐行读取帧缓冲区的多少,经过可能的数模转换传递给显示器,就展现出来了。这里只是简作描述,专业描述请自行查询。

设置阴影

好端端做法:

//阴影的颜色
self.imageView.layer.shadowColor= [UIColorblackColor].CGColor;
//阴影的透明度
self.imageView.layer.shadowOpacity=0.8f;
//阴影的圆角
self.imageView.layer.shadowRadius=4;
//阴影偏移量
self.imageView.layer.shadowOffset=CGSizeMake(0,0);

优化方案:
制止对shadowOffset间接修改,通过调用setShadowPath来提供一个CGPath给视图的Layer,向Core
Animation提供渲染的View的形态Shape,就会削减离屏渲染总结

[self.imageView.layer setShadowPath:[[UIBezierPath 
    bezierPathWithRect:myView.bounds] CGPath]];

补给:当使用阴影的视图形状暴发变化时,即shadowPath并不会跟随CALayer的bounds属性举办变更,所以在layer的bounds爆发变化之后需要手动更新shadowPath才能让其适配新的bounds。切切实实推荐看这篇著作

关于界面流畅倘若想要深层探索可以看 YYKit作者 写的稿子iOS
保持界面流畅的技能

。该作品从屏幕突显图像的法则,到立异的方案都有详实介绍。

谢谢各位,欢迎指教!

GPU屏幕渲染有两种办法:

(1)On-Screen Rendering (当前屏幕渲染) 

指的是GPU的渲染操作是在眼前用来呈现的屏幕缓冲区进行。

(2)Off-Screen Rendering (离屏渲染)

指的是在GPU在时下屏幕缓冲区以外开辟一个缓冲区举行渲染操作。

眼前屏幕渲染不需要额外创设新的缓存,也不需要打开新的上下文,相对于离屏渲染性能更好。然则受当前屏幕渲染的受制因素限制(唯有我上下文、屏幕缓存有限等),当前屏幕渲染有些情形下的渲染解决不了的,就动用到离屏渲染。

对照于近期屏幕渲染,离屏渲染的代价是很高的,首要反映在六个地点:

(1)创立新缓冲区

要想拓展离屏渲染,首先要成立一个新的缓冲区。

(2)上下文切换

离屏渲染的总体经过,需要频繁切换上下文环境:先是从当下屏幕(On-Screen)切换来离屏(Off-Screen),等到离屏渲染停止之后,将离屏缓冲区的渲染结果呈现到屏幕上有需要将上下文环境从离屏切换来目前屏幕。而上下文环境的切换是要付出很大代价的。

出于垂直同步的机制,假使在一个 HSync 时间内,CPU 或者 GPU
没有成功内容交给,则那一帧就会被裁撤,等待下一遍机会再展现,而此刻突显屏会保留以前的始末不变。这就是界面卡顿的因由。

既然如此离屏渲染这么耗性能,为何有这套机制吗?

稍微功力被认为无法从来显示于屏幕,而需要在另外地点做额外的处理预合成。图层属性的混合体没有预合成在此以前不可能直接在屏幕中绘制,所以就需要屏幕外渲染。屏幕外渲染并不代表软件绘图,不过它意味着图层必须在被出示在此之前在一个屏幕外上下文中被渲染(不论CPU如故GPU)。

下面的气象或操作会吸引离屏渲染:

为图层设置遮罩(layer.mask)

– 将图层的layer.masksToBounds / view.clipsToBounds属性设置为true

– 将图层layer.allowsGroupOpacity属性设置为YES和layer.opacity小于1.0

– 为图层设置阴影(layer.shadow *)。

– 为图层设置layer.shouldRasterize=true

– 具有layer.cornerRadius,layer.edgeAntialiasingMask,layer.allowsEdgeAntialiasing的图层

– 文本(任何类型,包括UILabel,CATextLayer,Core Text等)。

– 使用CGContext在drawRect
:方法中绘制大部分境况下会促成离屏渲染,甚至只有是一个空的落实。

优化方案

法定对离屏渲染爆发性能问题也进展了优化:

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

iOS 9.0
之后UIButton设置圆角会触发离屏渲染,而UIImageView里png图片设置圆角不会触发离屏渲染了,假设设置任何阴影效果之类的如故会触发离屏渲染的。

1、圆角优化

在APP开发中,圆角图形依然日常出现的。如若一个界面中只有微量圆角图片或许对性能没有充裕大的熏陶,可是当圆角图片相比较多的时候就会APP性能暴发强烈的影响。

咱俩设置圆角一般通过如下形式:

imageView.layer.cornerRadius = CGFloat(10);

imageView.layer.masksToBounds = YES;

这样处理的渲染机制是GPU在时下屏幕缓冲区外新开发一个渲染缓冲区举办工作,也就是离屏渲染,这会给大家带来额外的习性损耗,假诺这么的圆角操作达到一定数额,会触发缓冲区的频繁合并和上下文的的反复切换,性能的代价会宏观地显示在用户体验上——掉帧。

优化方案1:使用贝塞尔曲线UIBezierPath和Core Graphics框架画出一个圆角

UIImageView *imageView = [[UIImageView alloc]
initWithFrame:CGRectMake(100,100,100,100)];

imageView.image = [UIImage imageNamed:@”myImg”];

//先导对imageView举办绘画

UIGraphicsBeginImageContextWithOptions(imageView.bounds.size,NO,1.0);

//使用贝塞尔曲线画出一个圆形图

[[UIBezierPath
bezierPathWithRoundedRect:imageView.boundscornerRadius:imageView.frame.size.width]addClip];

[imageView drawRect:imageView.bounds];

imageView.image=UIGraphicsGetImageFromCurrentImageContext();

//停止画图

UIGraphicsEndImageContext();

[self.view addSubview:imageView];

优化方案2:使用CAShapeLayer和UIBezierPath设置圆角

UIImageView *imageView = [[UIImageView
alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];

imageView.image = [UIImage imageNamed:@”myImg”];

UIBezierPath *maskPath = [UIBezierPath
bezierPathWithRoundedRect:imageView.bounds
byRoundingCorners:UIRectCornerAllCorners
cornerRadii:imageView.bounds.size];

CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];

//设置大小

maskLayer.frame = imageView.bounds;

//设置图形样子

maskLayer.path = maskPath.CGPath;

imageView.layer.mask = maskLayer;

[self.view addSubview:imageView];

对此方案2急需解释的是:

CAShapeLayer继承于CALayer,能够采纳CALayer的拥有属性值;

CAShapeLayer需要贝塞尔曲线配合使用才有意义(也就是说才有功用)

应用CAShapeLayer(属于CoreAnimation)与贝塞尔曲线可以实现不在view的drawRect(继承于CoreGraphics走的是CPU,消耗的性能较大)方法中画出部分想要的图形

CAShapeLayer动画渲染直接付出到手机的GPU当中,相较于view的drawRect方法运用CPU渲染而言,其功用极高,能大大优化内存使用状态。

看来就是用CAShapeLayer的内存消耗少,渲染速度快,提出接纳优化方案2。

2、shadow优化

对此shadow,若是图层是个简易的几何图形或者圆角图形,我们得以通过安装shadowPath来优化性能,能大幅提升性能。示例如下:

imageView.layer.shadowColor=[UIColorgrayColor].CGColor;

imageView.layer.shadowOpacity=1.0;

imageView.layer.shadowRadius=2.0;

UIBezierPath *path=[UIBezierPathbezierPathWithRect:imageView.frame];

imageView.layer.shadowPath=path.CGPath;

咱俩还足以由此设置shouldRasterize属性值为YES来强制开启离屏渲染。其实就是光栅化(Rasterization)。既然离屏渲染这么不佳,为何我们还要强制开启呢?当一个图像混合了几个图层,每一遍运动时,每一帧都要再度合成这么些图层,卓殊消耗性能。当大家打开光栅化后,会在第一次暴发一个位图缓存,当再度利用时候就会复用这些缓存。但是假如图层暴发改变的时候就会重复爆发位图缓存。所以这么些职能相似不可能用于UITableViewCell中,cell的复用反而下跌了性能。最好用于图层较多的静态内容的图形。而且爆发的位图缓存的高低是有限量的,一般是2.5个屏幕尺寸。在100ms之内不利用这一个缓存,缓存也会被删去。所以大家要根据使用情况而定。

3、其他的片段优化指出

当我们需要圆角效应时,可以拔取一张中间透明图片蒙上去

应用ShadowPath指定layer阴影效果路径

接纳异步举行layer渲染(非死不可开源的异步绘制框架AsyncDisplay基特)

安装layer的opaque值为YES,裁减复杂图层合成

尽心尽力使用不包含透明(alpha)通道的图样资源

尽可能设置layer的大小值为整形值

一向让美工把图纸切成圆角举办体现,这是功效最高的一种方案

多多意况下用户上传图片展开显示,可以让服务端处理圆角

运用代码手动生成圆角Image设置到要显示的View上,利用UIBezierPath(CoreGraphics框架)画出来圆角图片

Core Animation工具检测离屏渲染

对此离屏渲染的检测,苹果为大家提供了一个测试工具Core
Animation。可以在Xcode->Open Develeper Tools->Instruments中找到

图片 1

Core Animation工具用来监测Core
Animation性能,提供可见的FPS值,并且提供多少个采用来测量渲染性能。如下图:

图片 2

下面我们来证实每个选项的效用:

Color Blended
Layers:这么些选项如果勾选,你能收看哪些layer是晶莹剔透的,GPU正在做混合总计。呈现绿色的就是透明的,青色就是不透明的。

Color Hits 格林 and Misses
Red:假诺勾选这些选项,且当我们代码中有设置shouldRasterize为YES,那么绿色代表没有复用离屏渲染的缓存,肉色则代表复用了缓存。大家自然期待可以复用。

Color Copied
Images:遵照法定的布道,当图片的水彩格式GPU不协助的时候,Core
Animation会

拷贝一份数据让CPU进行中转。例如从网络上下载了TIFF格式的图片,则需要CPU举办转账,这多少个区域会突显成肉色。还有一种状态会触发Core
Animation的copy方法,就是字节不对齐的时候。如下图:

图片 3

Color Immediately:默认境况下Core
Animation工具以每毫秒10次的频率更新图层调试颜色,如若勾选这么些选项则移除10ms的推迟。对少数情形需要这么,但是有可能影响健康帧数的测试。

Color Misaligned
Images:勾选此项,如果图片需要缩放则标记为香艳,假诺没有像素对齐则标记为藏蓝色。像素对齐我们早就在地点装有介绍。

Color Offscreen-Rendered
Yellow:用来检测离屏渲染的,如若呈现褐色,表示有离屏渲染。当然还要结合Color
Hits 格林 and Misses Red来看,是否复用了缓存。

Color OpenGL 法斯特(Fast) Path
Blue:这一个选项对那多少个使用OpenGL的图层才有用,像是GLKView或者
CAEAGLLayer,假若不显得棕色则代表使用了CPU渲染,绘制在了屏幕外,展现肉色代表正常。

Flash Updated
Regions:当对图层重绘的时候回显得灰色,假使反复暴发则会影响属性。可以用扩展缓存来加强性能。