Android 屏幕刷新机制

402 阅读2分钟

一、基本概率

  • 刷新率

    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信号来临时触发FrameDisplayEventReceiveronVsync 执行 doFrame方法, 会在最后执行对应类型 Callback 数组内的内容
    View绘制的流程:调用WindowManageraddView添加视图, 最终会通过ViewRootImplrequestLayout方法调用到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不相同

参考