zoukankan      html  css  js  c++  java
  • vsync信号产生与分发

    以下分析基于android 4.4代码

    vsync信号的产生、分发涉及到以下几个类,先主要了解下他们各自的功能:

    HWComposer:产生hardware vsync,post fb

    VSyncThread : 如果没有硬件支持,那么通过软件方式模拟hw vsync
    DispSync,DispSyncThread: 接受HWComposer的hw vsync信号作为校准,开始模拟产生vsync信号+偏移,并且会不时地进行校准,如postComposition后。
    EventControlThread:sf中的一个线程,仅用来控制hw vsync开关
    EventThread:负责分发vsync到sf或app

    DispSyncSource:EventThread和DispSyncThread的信息传递者, 把vsync信号从DispSyncThread传递到EventThread;同时可以用来设置相位偏移参数。

    在4.4之后,vsync信号不再完全由硬件产生,hw vsync信号主要用来做时间校准,vsync信号发生者是DispSyncThread, 当DispSyncThread产生的信号得到校准后,hw vsync会被关闭。

    几个问题分析:

    1.硬件vsync开启-关闭过程
    (1)HWComposer在hwc_composer_device_1中注册回调:
    mCBContext->procs.vsync = &hook_vsync;
    mHwc->registerProcs(mHwc, &mCBContext->procs);
    (2)vsync过来:HWComposer::hook_vsync => HWComposer::vsync
    (3)HWComposer::vsync=>mEventHandler.onVSyncReceived(disp, timestamp);
    mEventHandler即surfaceflinger
    (4)SurfaceFlinger::onVSyncReceived:

    needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); //加入样本,校准mPrimaryDispSync(DispSync),返回是否还需要hwsync
    if (needsHwVsync) {
    enableHardwareVsync(); //未同步,接续接受hw vsync
    } else {
    disableHardwareVsync(false); //已同步,关闭hw vsync
    }

    开启或关闭硬vsync:
    SurfaceFlinger::enableHardwareVsync() => mEventControlThread->setVsyncEnabled(true); //sf专门启动了一个线程EventControlThread来开关硬件vsync

    2.DispSyncThread 信号的产生:
    (1) 在sf类中声明一个成员变量:

    class SurfaceFlinger
    {
        ...
        DispSync mPrimaryDispSync;
        ...
    }

    (2) 构造函数里启动DispSyncThread线程

    DispSync::DispSync() {
        mThread = new DispSyncThread();
        mThread->run("DispSync", PRIORITY_URGENT_DISPLAY +         PRIORITY_MORE_FAVORABLE);
    
        reset();
        beginResync();
        ...
    }

    (3) 进入DispSyncThread::threadLoop(): 计算vsync周期,调用所有存在mEventListeners的Listener的callback

    fireCallbackInvocations()方法中调用callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
    mCallback的类型为DispSync::Callback

    (4) mEventListeners的注册通过调用DispSync::addEventListener()

    (5) 谁注册成为了vsync事件的监听者? 是DispSyncSource
    DispSyncSource继承自DispSync::Callback, 在它setVSysncEnabled(true)中调用:

    status_t err = mDispSync->addEventListener(mPhaseOffset,
    static_cast<DispSync::Callback*>(this));  //DispSyncSource把自己设为了DispSyncThread vsync信号的监听者
    
    所以vsync消息传到了DispSyncSource中的onDispSyncEvent(nsecs_t when)中:
    virtual void onDispSyncEvent(nsecs_t when) {
    sp<VSyncSource::Callback> callback;
    {
      Mutex::Autolock lock(mMutex);
      callback = mCallback;
    
      if (mTraceVsync) {
      mValue = (mValue + 1) % 2;
      ATRACE_INT("VSYNC", mValue);
      }
    }
    
    if (callback != NULL) {
      callback->onVSyncEvent(when); //又把vsync事件传递到了它自己的mCallback里, 这个mCallback 在EventThread::enableVSyncLocked()中设置, 就是EventThread, 这样vsync传递到了EventThread里
    }
    }

    (6)继续看谁又调用了DispSyncSource::setVSyncEnabled()?
    是EventThread::enableVSyncLocked():

    void EventThread::enableVSyncLocked() {
    if (!mUseSoftwareVSync) {
    // never enable h/w VSYNC when screen is off
      if (!mVsyncEnabled) {
      mVsyncEnabled = true;
      mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this)); //EventThread设为DispSyncSource的callback
      mVSyncSource->setVSyncEnabled(true);
      mPowerHAL.vsyncHint(true);
    }
    }
    mDebugVsyncEnabled = true;
    }

    (7)EventThread::enableVSyncLocked()又被EventThread::waitForEvent()调用

    Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
            DisplayEventReceiver::Event* event)
    {
     
        ...
        // Here we figure out if we need to enable or disable vsyncs
            if (timestamp && !waitForVSync) {
                // we received a VSYNC but we have no clients
                // don't report it, and disable VSYNC events
                disableVSyncLocked();
            } else if (!timestamp && waitForVSync) {
                // we have at least one client, so we want vsync enabled
                // (TODO: this function is called right after we finish
                // notifying clients of a vsync, so this call will be made
                // at the vsync rate, e.g. 60fps.  If we can accurately
                // track the current state we could avoid making this call
                // so often.)
                enableVSyncLocked();
            }
        ...      
    }

    waitForEvent()的逻辑是:

    接到vsync信号,但是当前EventThread中没有请求 vsync 的connection, EventThread向下不再监听vsync

    EventThread中有请求 vsync 的connection, EventThread继续监听vsync

    总结: vsync传递路径 DispSyncThread => DispSyncSource => EventThread
    DispSyncSource: 这个类比较简单,其实就是vsync传递者, 同时负责传递相位偏移phase offset到dispsyncThread。
    EventThread: 负责接收vsync, 分发给sf或者app


    所以在Sf init中的代码就比较好理解了

    // start the EventThread
    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    vsyncPhaseOffsetNs, true);
    mEventThread = new EventThread(vsyncSrc);
    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    sfVsyncPhaseOffsetNs, false);
    mSFEventThread = new EventThread(sfVsyncSrc);
    //上面代码注册了两个vsync信号的监听者, 当vsync产生时,分发给EventThread,这里有两个,一个处理sf,一个处理app
    
    mEventQueue.setEventThread(mSFEventThread); //
    
    mEventControlThread = new EventControlThread(this);
    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);

    3. 两个EventThread 线程是怎样把vsync分发给sf和app的?

    (1)app与EventThread
    EventThread里有一个 class Connection : public BnDisplayEventConnection,

    BnDisplayEventConnection 继承自 IDisplayEventConnection

    这个接口实现了:
    getDataChannel()
    setVsyncRate()
    requestNextVsync()

    App端请求vsync:

    app端通过DisplayEventReceiver 中的sp<IDisplayEventConnection> mEventConnection 来requestNextVsync
    mEventConnection实际上是BpDisplayEventConnection, 所以requestNextVsync是通过Binder通信从app端传递到EventThread并由它来处理。
    同时通过mEventConnection->getDataChannel(); 保存一个BitTube类型的mDataChannel。

    在EventThread端:
    app调用createEventConnection创建DisplayEventConnection时,EventThread将这个connection注册到它的mDisplayEventConnections集合里
    当vsync过来时,通知所有connection

    App端接受vsync是通过建立连接时保存的那个BitTube:

    //file:android_view_DisplayEventReceiver.cpp
    status_t NativeDisplayEventReceiver::initialize() {
      status_t result = mReceiver.initCheck();
      f (result) {
        ALOGW("Failed to initialize display event receiver, status=%d", result);
        return result;
      }
    
      int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT, // 监听BitTube的fd,有数据时,调用handler
      this, NULL);
      if (rc < 0) {
        return UNKNOWN_ERROR;
      }
      return OK;
    }

    所以app接受vsync信号是通过监听BitTube的fd, BitTube底层是通过socket实现。

    (2) sf与EventThread
    SurfaceFlinger::init()中调用mEventQueue.setEventThread(mSFEventThread);

    void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
    {
      mEventThread = eventThread;
      mEvents = eventThread->createEventConnection();
      mEventTube = mEvents->getDataChannel();
      mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,
      MessageQueue::cb_eventReceiver, this);
    }

    在sf进程中直接监听BitTube的fd,当有vsync过来时, 直接由SF的MessageQueue处理

  • 相关阅读:
    由前序和中序遍历结果构建二叉树
    Java学习笔记数组与ArrayList
    Java学习笔记字符串
    Java学习笔记关于默认类型或访问权限的总结
    javascript学习笔记之事件和事件处理
    2010年2月1日学习笔记
    Web.config保存整个站点的设置
    ANT的十五大最佳实践
    配置ajaxToolkit的方法【转】
    Java学习笔记Iterator迭代器(Ps.instanceof的用法)
  • 原文地址:https://www.cnblogs.com/hushpa/p/6579570.html
Copyright © 2011-2022 走看看