검색결과 리스트
글
SurfaceFlinger에서 DispSyncSource의 초기화 과정
DisplaySyncSource 클래스는 SurfaceFlinger.cpp 내에 소스코드가 존재합니다. 이는 이후 안드로이드의 VSync(수직동기화)를 수행하기 위해 따로 만들어지는 EventThread에서 적합하게 사용될 수 있도록 설계되어 있습니다. 전반적인 소스코드를 분석해 보도록 하겠습니다.
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 5 6 7 8 9 10 11 | // 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); mEventQueue.setEventThread(mSFEventThread); mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); | cs |
위의 DispSyncSource 생성자 내의 mPrimaryDispSync 변수는 DispSync 클래스의 변수입니다. DispSync 클래스에 대해 자세히 알고 싶으신 분은 아래 포스팅을 참조해 주시기 바랍니다.
Android에서 VSync 동작 원리 및 초기화 과정(3)
위의 소스코드를 통해 DisySyncSource 클래스가 VSync를 수행하기 위한 Thread를 위해 실행되고 있는 것을 알 수 있습니다. 위에서 생성되고 있는 DispSyncSource 클래스를 살펴보도록 하겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 | class VSyncSource : public virtual RefBase { public: class Callback: public virtual RefBase { public: virtual ~Callback() {} virtual void onVSyncEvent(nsecs_t when) = 0; }; virtual ~VSyncSource() {} virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(const sp<Callback>& callback) = 0; }; | cs |
/frameworks/native/services/surfaceflinger/DispSync.h
1 2 3 4 5 6 7 8 9 10 11 12 13 | class DispSync { public: class Callback: public virtual RefBase { public: virtual ~Callback() {}; virtual void onDispSyncEvent(nsecs_t when) = 0; }; .... } | cs |
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | class DispSyncSource : public VSyncSource, private DispSync::Callback { public: DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync) : mValue(0), mPhaseOffset(phaseOffset), mTraceVsync(traceVsync), mDispSync(dispSync) {} virtual ~DispSyncSource() {} virtual void setVSyncEnabled(bool enable) { // Do NOT lock the mutex here so as to avoid any mutex ordering issues // with locking it in the onDispSyncEvent callback. 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("VsyncOn", 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("VsyncOn", 0); } } virtual void setCallback(const sp<VSyncSource::Callback>& callback) { Mutex::Autolock lock(mMutex); mCallback = callback; } private: 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); } } int mValue; const nsecs_t mPhaseOffset; const bool mTraceVsync; DispSync* mDispSync; sp<VSyncSource::Callback> mCallback; Mutex mMutex; }; | cs |
위 과정을 거쳐 이후 EventThread를 통해 해당 내용들이 등록되게 됩니다. EventThread에 대한 자세한 사항은 아래 포스팅을 참조해 주시기 바랍니다.
SurfaceFlinger에서 EventThread의 초기화 과정
이후 EventThread가 초기화가 이루어진 후 waitForEvent() 함수가 호출됩니다. 이 때, 해당 함수 내에 있는 enableVSyncLocked() 함수가 실행되면 DispSyncSource에 Callback이 등록됩니다.
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | // This will return when (1) a vsync event has been received, and (2) there was // at least one connection interested in receiving it when we started waiting. Vector< sp<EventThread::Connection> > EventThread::waitForEvent( DisplayEventReceiver::Event* event) { Mutex::Autolock _l(mLock); Vector< sp<EventThread::Connection> > signalConnections; do { .... // 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(); .... } .... 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); mPowerHAL.vsyncHint(true); } } mDebugVsyncEnabled = true; } | cs |
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 | virtual void setCallback(const sp<VSyncSource::Callback>& callback) { Mutex::Autolock lock(mMutex); mCallback = callback; } | cs |
위 과정을 통하여 VSyncSource에 callback 함수가 등록됩니다. 해당 callback 함수는 아래와 같습니다.
/frameworks/native/services/surfaceflinger/EventThread.h
1 2 3 4 5 6 7 8 9 10 11 12 | class VSyncSource : public virtual RefBase { public: class Callback: public virtual RefBase { public: virtual ~Callback() {} virtual void onVSyncEvent(nsecs_t when) = 0; }; virtual ~VSyncSource() {} virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(const sp<Callback>& callback) = 0; }; | cs |
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 4 5 6 7 8 | 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(); } | cs |
Callback이 등록된 후 setVSyncEnable() 함수를 통해 DispSync Thread에 Listener를 등록합니다.
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | virtual void setVSyncEnabled(bool enable) { // Do NOT lock the mutex here so as to avoid any mutex ordering issues // with locking it in the onDispSyncEvent callback. 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("VsyncOn", 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("VsyncOn", 0); } } | cs |
위의 과정을 통해 DisySync 클래스의 addEventListener()함수를 통해 DisySync의 callback 함수가 등록되는 것을 보실 수 있습니다. 소스코드는 다음과 같습니다.
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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); } } | cs |
1 2 3 4 5 6 | status_t DispSync::addEventListener(nsecs_t phase, const sp<Callback>& callback) { Mutex::Autolock lock(mMutex); return mThread->addEventListener(phase, callback); } | cs |
위의 소스코드를 통해 DispSyncThread에 Event가 등록되는 것을 확인하실 수 있습니다.
/frameworks/native/services/surfaceflinger/DispSync.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class DispSyncThread: public Thread { .... status_t addEventListener(nsecs_t phase, const sp<DispSync::Callback>& callback) { Mutex::Autolock lock(mMutex); for (size_t i = 0; i < mEventListeners.size(); i++) { if (mEventListeners[i].mCallback == callback) { return BAD_VALUE; } } EventListener listener; listener.mPhase = phase; listener.mCallback = callback; // We want to allow the firstmost future event to fire without // allowing any past events to fire. Because // computeListenerNextEventTimeLocked filters out events within a half // a period of the last event time, we need to initialize the last // event time to a half a period in the past. listener.mLastEventTime = systemTime(SYSTEM_TIME_MONOTONIC) - mPeriod / 2; mEventListeners.push(listener); mCond.signal(); return NO_ERROR; } .... } | cs |
DispSync에 등록된 이벤트들은 이후 DispSyncThread에서 VSync 이벤트 Callback 발생시 실행됩니다.
/frameworks/native/services/surfaceflinger/DispSync.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class DispSyncThread: public Thread { .... Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) { Vector<CallbackInvocation> callbackInvocations; nsecs_t ref = now - mPeriod; for (size_t i = 0; i < mEventListeners.size(); i++) { nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], ref); if (t < now) { CallbackInvocation ci; ci.mCallback = mEventListeners[i].mCallback; ci.mEventTime = t; callbackInvocations.push(ci); mEventListeners.editItemAt(i).mLastEventTime = t; } } return callbackInvocations; } .... void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) { for (size_t i = 0; i < callbacks.size(); i++) { callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime); } } .... } | cs |
위의 과정을 거쳐 EventThread의 Callback 함수를 수행하게 되면 broadcast()함수에 의해 EventThread 내의 Thread들이 모두 깨어나게 됩니다. 이는 이후 postEvent() 함수를 호출하게 됩니다.
'안드로이드 > 프레임워크' 카테고리의 다른 글
Android에서 VSync 동작 원리 및 초기화 과정(5) (0) | 2015.09.20 |
---|---|
안드로이드 프레임워크 프로그래밍(25) [Native 단계에서 Looper의 동작 원리] (0) | 2015.09.16 |
SurfaceFlinger의 초기화 과정 흐름도 (0) | 2015.09.09 |
SurfaceFlinger에서 EventThread의 초기화 과정 (1) | 2015.09.08 |
안드로이드 프레임워크 프로그래밍(24) [BitTube 클래스] (2) | 2015.09.06 |