以及解决方案新普金娱乐,和大面积的离屏渲染Say

运动应用优化到终极关键依旧看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渲染(Facebook开源的异步绘制框架AsyncDisplayKit)

设置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 Green 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 法斯特 Path
Blue:这么些选项对那多少个运用OpenGL的图层才有用,像是GLKView或者
CAEAGLLayer,假使不出示黄色则表示使用了CPU渲染,绘制在了显示器外,显示紫色表示正常。

Flash Updated
Regions:当对图层重绘的时候回显得红色,如果反复暴发则会潜移默化属性。可以用扩充缓存来增长品质。

相关文章