一、基本概率
-
刷新率
1s 内屏幕显示的帧数,单位 Hz
-
帧率
1s 内CPU/GPU生成的帧数, 单位 fps
二、双缓存
-
画面撕裂 (tearing)
CPU ---> GPU ---> (buffer) ---> 显示器, CPU/GPU处理完数据放到buffer, 显示器取buffer的数据进行显示, 显示器刷新率是固定的, 当CPU/GPU处理的速度较慢时会出现只想buffer中填充了当前帧的部分数据,这时被显示器拿去显示
-
双缓存
为CPU/GPU和显示器分别准备两块缓存 Back Buffer 和 Frame Buffer, 等到Back Buffer数据准备好之后再和Frame Buffer交换进行显示(交换内存地址),不会存在数据不一致导致画面撕裂的问题
-
VSync
Back Buffer 和 Frame Buffer交换时机的问题,如果CPU/GPU处理速度比显示器快的话,当Back Buffer数据就绪的时候,Frame Buffer的数据还在被显示器使用, 这时候交换会存在问题, 需要在屏幕处理完这一帧数据之后才能交换
-
drawing VSync
VSync信号之后 CPU/GPU就可以立即处理下一帧数据了
三、三缓存
两次VSync间隔间GPU没处理完, 等到器处理完后又要等待下一次VSync才能交换缓存, 在此期间无法进行绘制,
可以再引入一个 Graphic Buffer, 再此期间 CPU 可以继续进行处理下一帧数据
四、Choreographer 编舞者
控制 VSync 信号发出后 CPU/GPU 立即执行下一帧的绘制工作
-
postCallback
注册一个VSync信号的监听, 在下次Vsync信号来临后执行对应的动作
Vsync信号来临时触发FrameDisplayEventReceiver的onVsync执行doFrame方法, 会在最后执行对应类型 Callback 数组内的内容
View绘制的流程:调用WindowManager的addView添加视图, 最终会通过ViewRootImpl的requestLayout方法调用到scheduleTraversals -
ViewRootImpl#scheduleTraversals
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; // 设置同步屏障 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); // 调用Choreographer的postCallback, 在下一个Vsync信号来后立即执mTraversalRunnable mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } } // mTraversalRunnable对应的类 //doTraversal ---> performTraversals ---> View绘制的三大流程 final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; // 移除同步屏障 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); if (mProfile) { Debug.startMethodTracing("ViewAncestor"); } // 执行measure、layout、draw 三大流程 performTraversals(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false; } } } -
postFrameCallback
与postCallback功能几乎一致, 参数不同, callbackType不相同