文章目录
一、 CPU 在图形处理领域的情况
二、 CPU 与 GPU 架构对比
三、 Android 布局显示到屏幕流程
四、 人眼的视觉相关分析
五、 渲染超时卡顿分析
六、 渲染过程与优化
一、 CPU 在图形处理领域的情况
GPU 出现前 CPU 在图形处理领域的情况 :
① 承担工作多 : GPU 没有出现之前 , CPU 要承担很多工作 , 如逻辑运算 , 内存管理 , 显示控制 , 界面渲染 等操作 ;
② 设备弊端 : 不能显示复杂的图形 , 不能运行渲染逼真的游戏 , 如大型 3D 游戏等 ;
③ CPU 在图形领域的性能瓶颈 : CPU 即使超过 2GHz 的主频 , 其运算能力并不能完全发挥出来 , 无法显示复杂画面 , 不能提高图形绘制的质量 ;
鉴于上述 CPU 的各种弊端 , 就有了 GPU 的设计 , CPU 将显示相关的计算交给 GPU 完成 ;
二、 CPU 与 GPU 架构对比
CPU 与 GPU 架构 :
① 控制单元 ( 黄色部分 ) : 控制器 , 控制 CPU 运行工作 , 执行如 取出指令操作 , 控制其它模块运行 ;
② 计算单元 ( 绿色部分 ) : 算术逻辑单元 , 负责数学运算 , 逻辑运算 ;
③ 存储单元 ( 橙色部分 ) : Cache 高速缓存器 , DRAM , 用于存储 CPU 运算信息 ;
CPU 与 GPU 对比 :
① 逻辑算术运算 : 图像处理时 , 大量使用逻辑运算 , 如 RGB 像素值的位运算 ; GPU 的计算单元多于 CPU , 因此 GPU 的逻辑运算能力强于 CPU ;
② 程序执行逻辑 : CPU 中控制单元与存储单元功能强大 , 控制程序运行的能力远远高于 GPU ;
③ 总结 : GPU 适合用于大量的复杂的算术逻辑计算 , 如图像运算 , 声音运算等 ; CPU 适合用于控制系统 , 应用运行 ;
三、 Android 布局显示到屏幕流程
Android 布局显示到屏幕流程 :
① 定义布局中的组件 : 在 xml 布局文件中定义 ImageView 布局 ;
② 加载组件到内存 : 通过 LayoutInflater 将该 ImageView 组件解析成 ImageView 对象 , 加载到内存中 , 该对象中封装了组件位置 , 显示图片等信息 ;
③ CPU 处理 : 将上述 ImageView 对象进行计算处理 , 最终得到该组件对应的多维向量图形 ( 使用向量表示的图形 ) ;
④ GPU 处理 : GPU 接收上述多维向量图形 , GPU 将该向量图进行栅格化 , 将向量图转为位图 ( 矢量图转为像素图 ) , 计算出对应屏幕上每个像素点显示的值 ;
⑤ 显示器显示 : GPU 向显示器推送位图 , 会判定前面的 4 44 个步骤花费时间是否小于 16ms , 如果小于该值 , 那么就显示该位图 , 如果大于该值 , 那么不绘制 , 等待下一帧位图绘制完成 , 这是为了避免显示卡顿而设计的机制 , 虽然丢了一帧数据 , 但是显示很流畅 ;
四、 人眼的视觉相关分析
1 . Android 刷新帧率 :
① 最低流畅帧率 : 保持画面流畅的最低帧率是 60FPS , 当帧率低于 60 FPS 时 , 就会画面卡顿的感觉 ;
② 60 帧率对应的每一帧刷新间隔 : 1000 60 = 16.66 \dfrac{1000}{60} = 16.66
60
1000
=16.66 , 即每隔 16.66 毫秒刷新一次 ;
③ Android 设备刷新机制 : Android 中每隔 16ms 就会发出 VSYNC 信号通知屏幕该进行渲染 , 每次渲染的时间都必须小于 16 毫秒 , 才能保证 60 FPS 的帧率 ; 如果渲染时间大于 16 毫秒 , 就无法保证 60 FPS 的帧率, 此时就会造成卡顿 ;
2 . 人眼对于各个帧率的接受程度 :
① 12 FPS : 达到这个帧率 , 人眼可以认为该图像是连续的动作 , 如 GIF 图像 , 翻动作小人书等 ;
② 24 FPS : 初期的电影动画的帧率 , 勉强接收 ;
③ 30 FPS : 早期的电子游戏 , 要求高于电影 ;
上面的三种都是人与视频内容不交互 , 或少量交互 , 人感觉不出来卡顿 ;
④ 60 FPS : 在交互频繁的游戏中 , 低于 60 FPS , 是可以感觉出来的 , 因此动作类的游戏尽量都要达到 60 FPS ;
⑤ 60 FPS 以上 : 60 FPS 与 144 FPS 是等效的 , 人眼察觉不到这个差异 ;
打游戏时 , 感觉很卡 , 说明帧率低于 60 帧了 , 越低迟滞感越强烈 ;
五、 渲染超时卡顿分析
1. VSync 信号 : Android 每隔 16 毫秒发出 VSync 信号 , 屏幕接收到该信号时 , 开始显示渲染好的位图 , CPU 和 GPU 开始渲染新的图像 ;
2. 渲染与显示时间固定 : 渲染开始 与 屏幕绘制的时间都是固定的 , 就是 VSync 信号发出时间 , 并且其间隔必须是 16 毫秒 , 在固定的时间开始渲染 , 在固定的 16 毫秒之后 , 显示到屏幕中 , 这样就是固定的 60Hz 的屏幕刷新频率 ;
3. 渲染提前完成 : 渲染可以提早完成 , 如 CPU 和 GPU 在 10 毫秒时已经渲染完毕 , 将向量图栅格化后的位图传递给屏幕 , 此时等待 6 毫秒后 , 屏幕触发显示操作 , 将已经渲染完毕的位图显示出来 ;
4. 显然超时未完成 : 在某个固定的时间 , 开始渲染图片 , CPU , GPU 对布局组件对应画面进行渲染后 , 如果从开始渲染 , 到显示器显示之间的时间间隔超过了 16 毫秒 , 屏幕在 16 毫秒的时刻接收 VSync 信号触发显示 , 但是此时还处于渲染阶段 , 没有将位图传递给屏幕 , 因此仍然显示上一帧图片 , 这里就少了一帧 , 变成了 59 Hz 的刷新频率 , 如果这种超时很多 , 变成 40Hz , 30Hz , 那就非常卡了 ;
上图中应该绘制 4 帧数据 , 但是实际上只绘制了 3 帧 , 实际刷新率少了一帧 ;
六、 渲染过程与优化
1. 渲染耗时分析 : 在开始渲染到显示的 16 毫秒时间内 , 主要有 3 33 个比较大块的时间 , 3 33 个耗时操作分别与 CPU 和 GPU 相关 ;
① 布局转换工作 : CPU 将布局中的 UI 组件对象转为多维向量图形 ( 纹理 / 多边形 / 向量 ) ;
② 图像传递工作 : CPU 传递向量图形给 GPU , CPU 与 GPU 之间数据传递非常耗时 ;
③ 图像绘制工作 : GPU 将该向量图形转为由像素点组成的位图 ;
2. 渲染优化 : 优化这里有引出了布局渲染优化 , 从上述 3 33 个角度去进行渲染优化 :
① 布局转换优化 : 减少 CPU 将 UI 组件对象转为多维向量图形的耗时 ;
② 图像传递优化 : 减少 CPU 传递给 GPU 的图像数据 ;
③ 图像绘制优化 : GPU 会执行 CPU 传递过来的任何计算工作 , 即使出现了图像覆盖重绘 , GPU 也会照常执行 , 减少 GPU 的图像覆盖重绘 ;