一 首先要了解计算机的渲染原理
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衔接的
*/