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處理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM