美文网首页
离屏渲染

离屏渲染

作者: 逃避不面对 | 来源:发表于2020-07-07 17:13 被阅读0次

    屏幕显示图像的原理:

    高中物理应该学过显示器是如何显示图像的:需要显示的图像经过电子枪以极快的速度进行一行一行的扫描,发射出来的电子撞击在屏幕的荧光剂上,荧光粉发光,就呈现了一帧画面,随后电子枪回到初始位置,因为人眼有视觉暂留效果,就形成了我们看到的图片或视频。

    GPU屏幕渲染有两种方式:

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

    指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区进行。GPU渲染过后,直接将结果放到帧缓存区,通过视频控制器读取后,显示到屏幕上。

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

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

    相比于当前屏幕渲染,离屏渲染的代价是很高的

    1.创建新缓冲区

    要想进行离屏渲染,首先要创建一个新的缓冲区。存储空间大小的上限是屏幕像素大小的2.5倍。

    2.上下文切换

    离屏渲染的过程,需要多次切换上下文环境:先从当前屏幕切换到离屏,当离屏渲染结束后,需要将渲染结果显示到屏幕上,又需要将上下文环境切换到当前屏幕。

    那么既然离屏渲染这么消耗性能,为什么又要使用离屏渲染呢?

    1.不得不使用离屏渲染:比如使用了特殊的渲染效果,所以必须用离屏缓冲区(offscreenBuffer)来保存中间状态,然后进行合成、裁切等操作后,才显示到屏幕上。这种情况不得不使用离屏渲染。

    2.效率优势:对于某些需要多次使用的效果,提前渲染到离屏缓冲区,使用的时候直接拿,通过复用来提升效率。

    造成离屏渲染的常见情况:

    - 为图层设置遮罩(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的图层

    - 绘制的文本的layer(任何种类,包括UILabel,CATextLayer,Core Text等)。

    - 使用CGContext在drawRect :方法中绘制大部分情况下会导致离屏渲染,甚至仅仅是一个空的实现。

    关于离屏渲染的优化:

    1.圆角的优化

    a.系统的优化

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

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

    b.使用贝塞尔曲线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];

    c.使用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];

    CAShapeLayer动画渲染直接提交到手机的GPU当中,相较于view的drawRect方法使用CPU渲染而言,其效率极高,能大大优化内存使用情况。推荐使用方案2

    d.从图的角度:美工出圆角图,美工出圆角遮罩图、用户上传的图片由服务器切好圆角图

    2.阴影优化shadow

    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;

    其他的优化:

    尽量使用不包含透明(alpha)通道的图片资源

    尽量设置layer的大小值为整形值

    使用异步进行layer渲染

    参考内容:https://www.jianshu.com/p/cff0d1b3c915

    相关文章

      网友评论

          本文标题:离屏渲染

          本文链接:https://www.haomeiwen.com/subject/uzkzqktx.html