一 首先要了解计算机的渲染原理

1.CPU:图片的解码、显示等

2.GPU:人脸识别、编码音视频,进行一些复杂的计算。

3.得到像素信息,然后显示到屏幕上,像素信息缓存到物理屏幕上。

  • CPU通过一系列的计算,然后GPU去渲染,通过帧缓存之后被视频控制器读取,最后显示到屏幕上。成像的原理是通过水平同步信号+垂直同步信号一帧帧的绘制而成。
  • 卡顿的原因:由于CPU要先计算-GPU渲染,假如CPU/GPU处理的事情较多,在固定的帧率下,未完成需要处理的事情,此时垂直同步信号已经到来,两者交叉就会造成视觉上的卡顿
  • 图片渲染的过程:以图片为例,顶点着色器:几何处理单元;光栅化:确定图片在屏幕上有哪些像素点需要填充;片元着色器:往屏幕上的颜色点进行填充。
  • CoreAnimation:渲染流水线:布局计算,Render Server图片解码,等待下一个loop执行Draw call。CP拿到位图、着色器进行绘制。

离屏渲染:对于前后依赖的图层,需要重新开辟一个空间,用于临时渲染,渲染完成后,在渲染到当前的缓冲区,这个叫临时渲染,也可以理解为离屏渲染。(多个图层重组)

设置cornerRadius 一定会触发离屏渲染吗?

记住原理:如果只是一个图层的话,是不会造成离屏渲染的,当出现多图片情况,因为GPU需要一个图层一个图层的绘制,最后合成一个图层。这种情况会造成离屏渲染。

二,UIView的渲染机制

/*

   当在操作 UI 时,比如改变了 Frame、更新了 UIView/CALayer 的层次时,或者手动调用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后,这个 UIView/CALayer 就被标记为待处理,并被提交到一个全局的容器去。

   苹果注册了一个 Observer 监听 BeforeWaiting(即将进入休眠) 和 Exit (即将退出Loop) 事件,回调去执行一个很长的函数:

   _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。这个函数里会遍历所有待处理的 UIView/CAlayer 以执行实际的绘制和调整,并更新 UI 界面。

   这个函数内部的调用栈大概是这样的:

_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()
   QuartzCore:CA::Transaction::observer_callback:
   CA::Transaction::commit();
   CA::Context::commit_transaction();
   CA::Layer::layout_and_display_if_needed();
   CA::Layer::layout_if_needed();
   [CALayer layoutSublayers];
   [UIView layoutSubviews];
   CA::Layer::display_if_needed();
   [CALayer display];
   [UIView drawRect];
   */

//    程序启动 UIApplicationMain()主线程:我是UI线程不能停,Runloop来和我一起吧。MainRunloop create and run MainRunloop:我想睡觉了,observer,你那边有事吗?observer:我去检查一下_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()我去看看 图层树中有没有待处理的对象有没有?CPU:我在更新图层树,一会交给Core Animation运走Core Animation:把待处理的图层对象 通过IPC发送到渲染服务进程GPU:渲染服务进程开始渲染工作GPU:Compositing\Offscreen Rendering 展示到屏幕 告诉runloop 让它睡会吧。有东西,我在叫你observer。yesno

XZZView *view = [[XZZView alloc] init];
   view.backgroundColor = [UIColor whiteColor];
   view.bounds = CGRectMake(0, 0, 100, 100);
   view.center = CGPointMake(100, 100);
    //注释掉,则不调用drawRect,所以addSubview会触发drawInRect
    [self.view addSubview:view];
    //在调用drawInRect之前,先调用了[UIView(CALayerDelegate) drawLayer:inContext:] 和 [CALayer drawInContext:]
    //drawrect方法内为何第一行代码总要获取图形的上下文???
    
    /*
     每一个UIView都有一个layer,每一个layer都有个content,这个content指向的是一块缓存,叫做backing store
     当UIView被绘制时(从 CA::Transaction::commit:以后),CPU执行drawRect,通过context将数据写入backing store
     当backing store写完后,通过render server交给GPU去渲染,将backing store中的bitmap数据显示在屏幕上
     所以在 drawRect 方法中 要首先获取 context
     */
    
    //图像的绘制???
    /*
     CPU会为layer分配一块内存来绘制bitmap,叫作backing store
     layer创建指向这块bitmap缓存区的指针,叫作CGContextRef
     通过CoreGraphic的api 也叫Quartz2D绘制bitmap
     将layer的content指向生成的bitmap
     CGContextRef的创建过程就是CPU的工程过程
     CPU讲view变成了bitmap完成了自己的工作
     */
    //view渲染机制和GPU之间关系???
    /*
     GPU的处理单位是texture
     控制GPU都是通过OpenGL来完成的,从bitmap到texture之间是通过Core Animati衔接的
     
     */