落叶知秋|程序员必懂的Android 技术之 VSYNC、 Choreographer 起源( 三 )


  • 在第二个 16 ms 时间段内 , Display 本应该显示 B 帧 , 但却因为 GPU 还在处理 B 帧 , 导致 A 帧被重复显示 。
  • 同理 , 在第二个 16 ms 时间段内 , CPU 无所事事 , 因为 A Buffer 被 Display 在使用 。 B Buffer 被 GPU 在使用 。 注意 , 一旦过了 VSYNC 时间点 , CPU 就不能被触发处理绘制工作了 。

为什么 CPU 不能在第二个 16ms 处理绘制工作呢?
原因是只有两个 Buffer , 缓冲区 B 中的数据还没有准备完成 , 所以只能继续展示 A 缓冲区的内容 , 这样缓冲区 A 和 B 都分别被显示设备和 GPU 占用 , CPU 则无法准备下一帧的数据 。
如果再提供一个缓冲区 , CPU、GPU 和显示设备都能使用各自的缓冲区工作 , 互不影响 。
简单来说 , 三重缓冲机制就是在双缓冲机制基础上增加了一个 Graphic Buffer 缓冲区 , 这样可以最大限度的利用空闲时间 , 带来的坏处是多使用的一个 Graphic Buffer 所占用的内存
落叶知秋|程序员必懂的Android 技术之 VSYNC、 Choreographer 起源由上图可知:
  • 在第二个 16ms 时间段 , CPU 使用 C Buffer 完成绘图工作 , 虽然还是会多显示一次 A 帧 , 但后续显示就比较顺畅了 , 有效避免 Jank 的进一步加剧 。
  • 注意:是不是 Buffer 越多越好呢?这个是否定的 , Buffer 正常还是两个 , 当出现 Jank 后三个足以 。

3、Choreographer
Choreographer 也是 Project Butter 计划新增的机制 , 用于配合系统的 VSYNC 中断信号 。
它本质是一个 Java 类 , 如果直译的话为舞蹈指导 , 这是一个极富诗意的表达 , 看到这个词不得不赞叹设计者除了 Coding 之外的广泛视野 。
舞蹈是有节奏的 , 节奏使舞蹈的每个动作更加协调和连贯;视图刷新也是如此 。
Choreographer 可以接收系统的 VSYNC 信号 , 统一管理应用的输入、动画和绘制等任务的执行时机 。 Android 的 UI 绘制任务将在它的统一指挥下 , 井然有序的完成 。 业界一般通过它来监控应用的帧率 。
Choreographer 的构造方法:
private Choreographer(Looper looper, int vsyncSource) {// 当前线程的LoopermLooper = looper;// 创建该Looper的HandlermHandler = new FrameHandler(looper);// 是否开启VSYNC , 开启VSYNC后将通过FrameDisplayEventReceiver接受// VSYNC脉冲mDisplayEventReceiver = USE_VSYNC? new FrameDisplayEventReceiver(looper, vsyncSource): null;mLastFrameTimeNanos = Long.MIN_VALUE;// 计算一帧的时间// Android手机屏幕采用60Hz的刷新频率// 这里是纳秒 ≈16000000ns 还是16msmFrameIntervalNanos = (long)(1000000000 / getRefreshRate());// 创建一个CallbackQueu的数组 , 默认为4// CallbackQueue中存放要执行的输入、动画、遍历绘制等任务// 也就是 CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSALmCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];for (int i = 0; i <= CALLBACK_LAST; i++) {mCallbackQueues[i] = new CallbackQueue();}// b/68769804: For low FPS experiments.setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));}Choreographer 是线程单例的 , 而且必须要和一个 Looper 绑定 , 因为其内部有一个 Handler 需要和当前绘制线程的 Looper 绑定 。
DisplayEventReceiver 是一个 abstract class , 在其构造方法内会通过 JNI 创建一个 IDisplayEventConnection 的 VSYNC 的监听者 。
另外 DisplayEventReceiver 中包含两个非常重要的方法:一个用于需要绘制任务时 , 申请 VSYNC 信号的 scheduleVsync 方法 , 另一个用于接收 VSYNC 信号的 onVsync 方法 。 FrameDisplayEventReceiver 是 DisplayEventReceiver 的唯一实现类 , 并重写 onVsync 方法用于通知 Choreographer 。


推荐阅读