美文网首页专注iOS开发
Quartz2D的CALayer重绘存在的问题

Quartz2D的CALayer重绘存在的问题

作者: naiyi | 来源:发表于2017-11-18 12:03 被阅读155次

    iOS的视图绘制通常有三种方式,CoreGraphics、Quartz2D和OpenGL ES,性能从低到高。

    CoreGraphics主要是覆盖UIView的drawRect的方式来实现视图绘制,而UIView的下层绘制是由CALayer提供的,UIView只是在CALayer上添加了事件捕获来响应用户交互操作。那么按道理说CoreGraphics与Quartz2D的性能差距应该不大,但事实并不是这样。

    参考以下内容:
    http://bihongbo.com/2016/01/03/memoryGhostdrawRect/
    http://bihongbo.com/2016/01/11/memoryGhostMore/
    

    可见如果drawRect使用不当,会造成大量的内存反复申请和释放(用来构建位图和刷新),而当该视图在不断变化,需要与屏幕有同样刷新率的情况下,这个性能是远远不足以达到的。这时候可以使用Quartz2D的一系列CALayer子类来实现。

    新的问题

    刚开始使用CAShapeLayer绘制图形的时候,还是蛮惊喜的,速度很快内存也几乎没有变化。但是不久后就发现了一个新问题。那就是在低端一些的机型上(其实也不是很低端,iPhone6p就会出现问题。而且即使是SE、6S、7等机型,如果重绘面积大、路径复杂,一样会出现同样的问题,只不过程度轻一些,应该是因为CPU性能的提升),如果视图内容是不断变化的,并且想以屏幕刷新率60fps一样的频率刷新视图内容,则会出现明显的丢帧卡顿现象,也就是说CAShapeLayer的重绘依然是一个很昂贵的操作,即使其矢量图的绘制方式在内存利用率上远远超过CoreGraphics的位图实现,但重绘机制依然是没有办法越过的障碍。

    参考以下内容:
    https://stackoverflow.com/questions/2720804/how-much-more-complex-is-it-to-draw-simple-curves-lines-and-circles-in-opengl-e/
    https://stackoverflow.com/questions/2720642/what-is-faster-drawing-or-compositing/
    

    I assume the reason you want to switch to OpenGL is to accelerate the animation of your drawn elements. In that question, you were attempting to animate by redrawing your UIView's contents with Quartz every frame. That will be incredibly slow, because of the way that the iPhone's drawing system works. Every frame, your view's backing layer would need to be converted to a texture and re-uploaded to the GPU, a very slow set of operations.

    提问者的做法是尝试通过Quartz2D在每一帧重绘视图内容的方式来实现动画。但受限于iPhone的绘制系统工作机制,这个行为会极其的缓慢。因为每一帧内容都需要先被转换成纹理然后再重新上传GPU,这是一系列耗时操作。

    Compositing is faster, by far. On the iPhone, content is drawn into a CALayer (or into a UIView's backing CALayer) using Quartz drawing calls or from a bitmapped image. This layer is then rasterized and effectively cached as an OpenGL texture on the GPU.

    This drawing and caching operation is very expensive, but once the layer is on the GPU, it can be moved around, scaled, rotated, etc. in a hardware-accelerated manner. All the GPU has to do while the layer is animating is to composite it with the other onscreen layers every frame. This is why Core Animation can do 50 layers animating around the screen at 60 FPS on even the oldest iPhone models.

    Layers and views only redraw themselves when prompted, or if resized when their needsDisplayOnBoundsChange property is set to YES. The drawing system is set up this way because of how expensive it is to redraw and recache the layer contents. If you can, avoid redrawing your layer content regularly, but instead split it into layers or views that you can animate around individually using Core Animation. If you need to animate a changing shape, look to CAShapeLayer, which makes this much more efficient than simply redrawing every frame.

    目前混合比绘制快的多。在iPhone上,CALayer上的内容是通过Quartz绘制函数的调用或者通过一个位图图片绘制的。然后layer被栅格化然后作为OpenGL的纹理被高效缓存到GPU上。
    绘制和缓存操作非常昂贵,但是一旦layer发送到了GPU上,就可以通过硬件加速的方式进行评议、缩放、旋转等变化。GPU在layer动画的过程中唯一需要做的就是在每一帧的时候把这个layer跟其他屏幕可见layer进行混合。这就是为什么Core Animation即使在最古老的iPhone机型上也能做到以60FPS的刷新率同时动画屏幕上的50个以上的layers。
    layers和views只有接到通知的时候才进行重绘,另外如果needsDisplayOnBoundsChange被设置成true那么尺寸变化的时候也会重绘。之所以设计这种绘制系统就是因为重绘和缓存layer的内容十分消耗资源。应该尽可能的避免频繁重绘layer的内容,而是应该把内容切分到不同的layers或者views里面,然后独立对每个layer使用Core Animatio进行动画。如果需要动画一个变化的图形可以使用CAShapeLayer,这个比重绘每一帧高效的多。

    结论

    所以,当使用CALayer绘制产生性能问题的时候,就只能采用OpenGL ES了。总体来说的原则是,使用Quartz2D和Core Animation能解决需求并没有性能问题的情况下,优先使用它。若性能不满足则换OpenGL ES,没有什么理由来使用CoreGraphics,除非绘制任务很轻松没有太大区别(只绘制一次不刷新面积也很小的情况下)。

    相关文章

      网友评论

        本文标题:Quartz2D的CALayer重绘存在的问题

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