Android SurfaceFlinger服務(六) ----- VSync信號的分發

HWComposer模塊產生VSync信號後要經過分發才能送達到關心VSync事件的模塊中去。VSync信號分發大致流程爲HWComposer->SurfaceFlinger->DispSync->DispSyncSource->各個具體模塊。下面具體分析下這個流程。

在上一篇文章中分析到硬件或者軟件VSync信號產生時,會回調SurfaceFlinger的onVSyncReceived函數,來看看這個函數:

void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
    bool needsHwVsync = false;

    { // Scope for the lock
        Mutex::Autolock _l(mHWVsyncLock); 
        if (type == 0 && mPrimaryHWVsyncEnabled) {
            needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
        }
    }  

    if (needsHwVsync) {
        enableHardwareVsync();
    } else {
        disableHardwareVsync(false);
    }  
}
  • mPrimaryDispSync類型爲DispSync,在構造的時候會創建DispSyncThread
DispSync::DispSync() :
        mRefreshSkipCount(0),
        mThread(new DispSyncThread()) {

    mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);

    reset();
    beginResync();

    if (kTraceDetailedInfo) {
        // If we're not getting present fences then the ZeroPhaseTracer
        // would prevent HW vsync event from ever being turned off.
        // Even if we're just ignoring the fences, the zero-phase tracing is
        // not needed because any time there is an event registered we will
        // turn on the HW vsync events.
        if (!kIgnorePresentFences) {   
            addEventListener(0, new ZeroPhaseTracer());
        }
    }
}
  • 調用DispSync的addResyncSample方法,最終會去喚醒DispSyncThread線程
bool DispSync::addResyncSample(nsecs_t timestamp) {
    Mutex::Autolock lock(mMutex);

    size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
    mResyncSamples[idx] = timestamp;

    if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
        mNumResyncSamples++;
    } else {
        mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES;
    }

    updateModelLocked();

    if (mNumResyncSamplesSincePresent++ > MAX_RESYNC_SAMPLES_WITHOUT_PRESENT) {
        resetErrorLocked();
    }

    if (kIgnorePresentFences) {
        // If we don't have the sync framework we will never have
        // addPresentFence called.  This means we have no way to know whether
        // or not we're synchronized with the HW vsyncs, so we just request
        // that the HW vsync events be turned on whenever we need to generate
        // SW vsync events.
        return mThread->hasAnyEventListeners();
    }

    return mPeriod == 0 || mError > kErrorThreshold;
}
  • 調用updateModelLocked函數
  • 計算是否需要開啓硬件VSync,進行同步
void DispSync::updateModelLocked() {
    if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
        
        ......
        
        mThread->updateModel(mPeriod, mPhase);
    }
}
  • 成員變量mThread爲DispSyncThread類的對象
  • 調用DispSyncThread類pdateModel方法
void updateModel(nsecs_t period, nsecs_t phase) {
        Mutex::Autolock lock(mMutex);
        mPeriod = period;
        mPhase = phase;
        mCond.signal();
    }
  • 該方法主要設置成員變量mPeriod、mPhase
  • 然後在喚醒線程循環
virtual bool threadLoop() {
        status_t err;
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        nsecs_t nextEventTime = 0;

        while (true) {
            Vector<CallbackInvocation> callbackInvocations;

            nsecs_t targetTime = 0;

            { // Scope for lock
                Mutex::Autolock lock(mMutex);

                ......

                callbackInvocations = gatherCallbackInvocationsLocked(now);
            }

            if (callbackInvocations.size() > 0) {
                fireCallbackInvocations(callbackInvocations);
            }
        }

        return false;
    }
  • 通過gatherCallbackInvocationsLocked得到監聽者集合
  • 通過fireCallbackInvocations調用監聽者回調函數

DispSync的回調函數在哪裏註冊,我們在看看DispSyncSource的setVSyncEnabled函數

virtual void setVSyncEnabled(bool enable) {
        Mutex::Autolock lock(mVsyncMutex);
        if (enable) {
            status_t err = mDispSync->addEventListener(mPhaseOffset,
                    static_cast<DispSync::Callback*>(this));
            if (err != NO_ERROR) {             
                ALOGE("error registering vsync callback: %s (%d)",
                        strerror(-err), err);                                                                                                                                                
            }
            //ATRACE_INT(mVsyncOnLabel.string(), 1);                                                                                                                                         
        } else {
            status_t err = mDispSync->removeEventListener(
                    static_cast<DispSync::Callback*>(this));
            if (err != NO_ERROR) {             
                ALOGE("error unregistering vsync callback: %s (%d)",
                        strerror(-err), err);                                                                                                                                                
            }
            //ATRACE_INT(mVsyncOnLabel.string(), 0);                                                                                                                                         
        }
        mEnabled = enable;
    }
  • DispSyncSource類繼承於DispSync::Callback
  • 調用DispSync->addEventListener註冊回調,當DispSyncSource收到DispSync的VSync信號時,會回調整onDispSyncEvent函數
virtual void onDispSyncEvent(nsecs_t when) {
        sp<VSyncSource::Callback> callback;
        {
            Mutex::Autolock lock(mCallbackMutex);
            callback = mCallback;

            if (mTraceVsync) {
                mValue = (mValue + 1) % 2;
                ATRACE_INT(mVsyncEventLabel.string(), mValue);
            }
        }

        if (callback != NULL) {
            callback->onVSyncEvent(when);
        }
    }
  • 這個函數最終還是調用VSyncSource::Callback的onVSyncEvent函數。
  • VSyncSource::Callback函數的註冊是通過調用DispSyncSource的setCallback註冊。

DispSyncSource的setCallback函數在哪裏調用的呢,要解答這個問題,還是得回到SurfaceFlinger的init函數裏,以sfVsyncSrc爲例。

void SurfaceFlinger::init() {
    
    ......
    
    // start the EventThread
    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            vsyncPhaseOffsetNs, true, "app");
    mEventThread = new EventThread(vsyncSrc);
    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            sfVsyncPhaseOffsetNs, true, "sf");
    mSFEventThread = new EventThread(sfVsyncSrc);
    mEventQueue.setEventThread(mSFEventThread);

    ......
}
  • 以sfVsyncSrc爲參數創建EventThread對象
  • 在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));
            mVSyncSource->setVSyncEnabled(true);
        }
    }  
    mDebugVsyncEnabled = true;
    sendVsyncHintOnLocked();
}
  • EventThread繼承VSyncSource::Callback接口,實現了onVSyncEvent函數
  • 調用mVSyncSource的setCallback函數設置回調
  • 調用mVSyncSource的setVSyncEnabled函數使能VSync信號的監聽
void EventThread::onVSyncEvent(nsecs_t timestamp) {
    Mutex::Autolock _l(mLock);
    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
    mVSyncEvent[0].header.id = 0;  
    mVSyncEvent[0].header.timestamp = timestamp;
    mVSyncEvent[0].vsync.count++;  
    mCondition.broadcast();
}
  • EventThread收到VSync信號後,發送廣播消息,喚醒相關線程
  • 最終EventThread將VSnc信號傳遞給MessageQueue

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章