当CPU和GPU渲染图像的时间过长,在下一个垂直同步信号来的时候,GPU并没有处理完一帧的数据,帧缓冲区也就没有交换,视频控制器就会显示原来缓冲区的内容
三缓冲区
从上图可以看出,CPU和GPU是在垂直同步信号到来的时候才开始渲染的工作,为了减少掉帧的情况,引入了三缓冲区
A:显示到屏幕
B:提前渲染号
C:正在渲染
其实相当于预加载,充分利用CPU和GPU的空闲时间,提前渲染好一帧B(同时也会带来画面延迟,当然1帧的延迟是可以接受的),多留出了一帧的时间,即使在渲染C的时候出现了一次掉帧,依然能刘畅渲染,这种情况大大减小了掉帧的可能
但如果渲染C的时间过长(掉多帧),依然会带来掉帧的问题,三缓冲区本质上并不解决掉帧的问题,只是缓解
为了解决掉帧的问题,我们只能尽可能优化我们的代码,减少CPU和GPU的渲染时间
iOS的渲染框架
渲染框架
可以看到在iOS中的CoreGraphics, CoreAnimation, CoreImage都是通过OpenGL/Metal进行渲染的,我们的App也可以使用OpenGL/Metal来操作GPU进行渲染
CoreAnimation 渲染流⽔线
CoreAnimation会在Runloop注册一个Observer监听触摸事件,当点击事件到来的时候,Runloop会被唤醒处理相关的业务逻辑(UIView的创建,修改,添加动画等)
最终会在CALayer通过CATransaction提交到RenderServer中,RenderServer会对图片进行解码,并等待下一个VSync的到来
VSync信号到来后,RenderService会通过OpenGL/Metal做一些绘制操作,然后把处理完的数据(纹理,顶点,着色器等)提交给GPU
GPU通过下面渲染流程程(顶点数据->顶点着⾊器->⽚元着⾊器),渲染到帧缓冲区,然后交换帧缓冲区(双缓冲区)
下一个VSync信号到来的时候,视频控制器读取帧缓冲区的数据显示到屏幕上
如果此处有动画,CoreAnimation会通过DisplayLink等机制多次触发相关流程
渲染流程CPU阶段
布局(Frame): layoutSubviews, addSubview
显示(Core Graphics): drawRect, 绘制字符串
准备(QuartzCore/Core Animation):图片decode
提交:通过IPC提交(打包好的layers以及动画属性)给OpenGL/Metal,递归提交subview的layers
OpenGL ES/Metal阶段,主要是对图层进行取色,采样,生成纹理,绑定数据,生成前后帧缓存,为GPU渲染做准备
生成(Generate)
绑定(Bind)
缓存数据(Buffer Data)
启用(Enable)
设置指针(Set Pointers)
绘图(Draw)
清除(Delete)
GPU阶段
接收提交的纹理(Texture)和顶点描述(三角形)
应用变换(transform)
合并渲染(离屏渲染等)