Android6.0 顯示系統(五) SurfaceFlinger服務
SurfaceFlinger是一個獨立的程式,我們來看下init.rc關於SurfaceFlinger的程式碼,我們可以看到SurfaceFlinger是屬於core服務的。
- service surfaceflinger /system/bin/surfaceflinger
- class core
- user system
- group graphics drmrpc
- onrestart restart zygote
- writepid /dev/cpuset/system-background/tasks
一、SurfaceFlinger的啟動過程
SurfaceFlinger的main函式在framework/native/services/surfaceflinger/main_surfaceflinger.cpp中
- int main(int, char**) {
- // When SF is launched in its own process, limit the number of
- // binder threads to 4.
- ProcessState::self()->setThreadPoolMaxThreadCount(4);//設定了Binder執行緒池最大執行緒為4
- // start the thread pool
- sp<ProcessState> ps(ProcessState::self());
- ps->startThreadPool();
- // instantiate surfaceflinger
- sp<SurfaceFlinger> flinger = new SurfaceFlinger();//建立SurfaceFlinger物件
- setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
- set_sched_policy(0, SP_FOREGROUND);
- // initialize before clients can connect
- flinger->init();//呼叫SurfaceFlinger的init函式
- // publish surface flinger
- sp<IServiceManager> sm(defaultServiceManager());
- sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);//像serviceManager註冊SurfaceFlinger服務
- // run in this thread
- flinger->run();//執行
- return 0;
- }
在主函式中先設定了該程式的binder執行緒池最大數為4,然後建立了SurfaceFlinger物件,並且呼叫了其init函式,接著把SurfaceFlinger服務註冊到ServiceManager中,然後呼叫了run方法。
我們先來看下init函式
- void SurfaceFlinger::init() {
- ALOGI( "SurfaceFlinger's main thread ready to run. "
- "Initializing graphics H/W...");
- Mutex::Autolock _l(mStateLock);
- // initialize EGL for the default display 將EGL初始化成預設的顯示
- mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(mEGLDisplay, NULL, NULL);
- // 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);
- // Initialize the H/W composer object. There may or may not be an
- // actual hardware composer underneath.
- mHwc = new HWComposer(this,//顯示硬體抽象類
- *static_cast<HWComposer::EventHandler *>(this));
- // get a RenderEngine for the given display / config (can't fail)
- mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
- // retrieve the EGL context that was selected/created
- mEGLContext = mRenderEngine->getEGLContext();
- LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
- "couldn't create EGLContext");
- // initialize our non-virtual displays 初始化顯示裝置
- for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
- // set-up the displays that are already connected
- if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
- // All non-virtual displays are currently considered secure.
- bool isSecure = true;
- createBuiltinDisplayLocked(type);
- wp<IBinder> token = mBuiltinDisplays[i];
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer,
- new GraphicBufferAlloc());
- sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
- consumer);
- int32_t hwcId = allocateHwcDisplayId(type);
- sp<DisplayDevice> hw = new DisplayDevice(this,
- type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
- fbs, producer,
- mRenderEngine->getEGLConfig());
- if (i > DisplayDevice::DISPLAY_PRIMARY) {
- // FIXME: currently we don't get blank/unblank requests
- // for displays other than the main display, so we always
- // assume a connected display is unblanked.
- ALOGD("marking display %zu as acquired/unblanked", i);
- hw->setPowerMode(HWC_POWER_MODE_NORMAL);
- }
- mDisplays.add(token, hw);
- }
- }
- // make the GLContext current so that we can create textures when creating Layers
- // (which may happens before we render something)
- getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
- mEventControlThread = new EventControlThread(this);
- mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
- // set a fake vsync period if there is no HWComposer
- if (mHwc->initCheck() != NO_ERROR) {
- mPrimaryDispSync.setPeriod(16666667);
- }
- // initialize our drawing state
- mDrawingState = mCurrentState;
- // set initial conditions (e.g. unblank default device)
- initializeDisplays();//初始化顯示裝置
- // start boot animation
- startBootAnim();//啟動開機動畫
- }
init函式主要工作:
1.初始化OpenGL ES圖形庫。
2. 建立顯示裝置的抽象代表,負責和顯示裝置打交道。
3. 建立顯示裝置物件。
4. 啟動EventThread。監聽和處理SurfaceFlinger中的事件。
5.設定軟體VSync訊號週期。
6.初始化顯示裝置,呼叫initializeDisplays完成。
7.啟動開機動畫,呼叫了startBootAnim函式,只是設定了兩個屬性,其中一個ctl.start是啟動了bootanim程式。
- void SurfaceFlinger::startBootAnim() {
- // start boot animation
- property_set("service.bootanim.exit", "0");
- property_set("ctl.start", "bootanim");
- }
二、訊息和事件分發 MessageQueue和EventThread
MessageQueue和用於訊息和事件的分發,這個和之前部落格分析過得訊息機制原理差不多。
我們先來看看MessageQueue的主要成員變數
- class MessageQueue {
- ......
- sp<SurfaceFlinger> mFlinger;//指向SurfaceFlinger
- sp<Looper> mLooper;//訊息機制Looper物件
- sp<EventThread> mEventThread;//關聯的EventThread
- sp<IDisplayEventConnection> mEvents;
- sp<BitTube> mEventTube;
- sp<Handler> mHandler;//訊息處理器
在SurfaceFlinger中有一個型別為MessageQueue的成員變數mEventQueue,在SurfaceFlinger的onFirstRef函式中會呼叫其init函式
- void SurfaceFlinger::onFirstRef()
- {
- mEventQueue.init(this);
- }
- void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
- {
- mFlinger = flinger;
- mLooper = new Looper(true);
- mHandler = new Handler(*this);
- }
- class Handler : public MessageHandler {
- enum {
- eventMaskInvalidate = 0x1,//invalidate訊息
- eventMaskRefresh = 0x2,//重新整理訊息
- eventMaskTransaction = 0x4
- };
- MessageQueue& mQueue;
- int32_t mEventMask;
- public:
- Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
- virtual void handleMessage(const Message& message);
- void dispatchRefresh();
- void dispatchInvalidate();
- void dispatchTransaction();
- };
我們再來看在SurfaceFlinger主函式最後呼叫了下面方法。
- flinger->run();
SurfaceFlinger::run程式碼如下
- void SurfaceFlinger::run() {
- do {
- waitForEvent();
- } while (true);
- }
waitForEvent函式如下:
- void SurfaceFlinger::waitForEvent() {
- mEventQueue.waitMessage();
- }
然後又呼叫了EventQueue的waitMessage方法,記住這裡是在主執行緒中迴圈呼叫的。
下面我們來看下waitMessage方法,flushCommands之前在分析Binder的部落格中有提到,主要是清理工作的,和Binder驅動的互動關了。而pollOnce是訊息機制,主要呼叫了epoll_wait函式,會阻塞,阻塞完了會分發訊息佇列中的訊息。這裡的訊息只有自己在Handler中發的訊息,還有在setEventThread中自己新增的fd。
- void MessageQueue::waitMessage() {
- do {
- IPCThreadState::self()->flushCommands();
- int32_t ret = mLooper->pollOnce(-1);
- switch (ret) {
- case Looper::POLL_WAKE:
- case Looper::POLL_CALLBACK:
- continue;
- case Looper::POLL_ERROR:
- ALOGE("Looper::POLL_ERROR");
- case Looper::POLL_TIMEOUT:
- // timeout (should not happen)
- continue;
- default:
- // should not happen
- ALOGE("Looper::pollOnce() returned unknown status %d", ret);
- continue;
- }
- } while (true);
- }
下面是Handler中傳送訊息,這個會在pollOnce中處理。
- void MessageQueue::Handler::dispatchRefresh() {
- if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
- mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
- }
- }
- void MessageQueue::Handler::dispatchInvalidate() {
- if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
- mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
- }
- }
- void MessageQueue::Handler::dispatchTransaction() {
- if ((android_atomic_or(eventMaskTransaction, &mEventMask) & eventMaskTransaction) == 0) {
- mQueue.mLooper->sendMessage(this, Message(MessageQueue::TRANSACTION));
- }
- }
在SurfaceFlinger的init函式還呼叫瞭如下函式
- mSFEventThread = new EventThread(sfVsyncSrc);
- mEventQueue.setEventThread(mSFEventThread);
我們來看setEventThread函式會呼叫Looper的addFd,這個最終也會在pollOnce中執行。mEventThread是一個EventThread物件,呼叫createEventConnection來建立一個連線。EventThread是一個執行緒類用來分發VSync訊息。這個我們後面講解VSync訊號的時候還會詳細分析。
- void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
- {
- mEventThread = eventThread;
- mEvents = eventThread->createEventConnection();
- mEventTube = mEvents->getDataChannel();
- mLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT,
- MessageQueue::cb_eventReceiver, this);
- }
三、顯示裝置 DisplayDevice類
DisplayDevice是顯示裝置的抽象,定義了3中型別的顯示裝置。
1.DISPLAY_PRIMARY:主顯示裝置,通常是LCD屏
2.DISPLAY_EXTERNAL:擴充套件顯示裝置。通過HDMI輸出的顯示訊號
3.DISPLAY_VIRTUAL:虛擬顯示裝置,通過WIFI輸出訊號
這3鍾裝置,第一種是基本配置,另外兩種需要硬體支援。這裡我們主要講解第一種。
SurfaceFlinger中需要顯示的圖層(layer)將通過DisplayDevice物件傳遞到OpenGLES中進行合成,合成之後的影象再通過HWComposer物件傳遞到Framebuffer中顯示。DisplayDevice物件中的成員變數mVisibleLayersSortedByZ儲存了所有需要顯示在本顯示裝置中顯示的Layer物件,同時DisplayDevice物件也儲存了和顯示裝置相關的顯示方向、顯示區域座標等資訊。
上節在SurfaceFlinger的init函式中有一段程式碼來建立DisplayDevice物件
- for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
- // set-up the displays that are already connected
- if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
- // All non-virtual displays are currently considered secure.
- bool isSecure = true;
- createBuiltinDisplayLocked(type);//給顯示裝置分配一個token
- wp<IBinder> token = mBuiltinDisplays[i];
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer,
- new GraphicBufferAlloc());
- sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
- consumer);
- int32_t hwcId = allocateHwcDisplayId(type);
- sp<DisplayDevice> hw = new DisplayDevice(this,
- type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
- fbs, producer,
- mRenderEngine->getEGLConfig());
- if (i > DisplayDevice::DISPLAY_PRIMARY) {
- // FIXME: currently we don't get blank/unblank requests
- // for displays other than the main display, so we always
- // assume a connected display is unblanked.
- ALOGD("marking display %zu as acquired/unblanked", i);
- hw->setPowerMode(HWC_POWER_MODE_NORMAL);
- }
- mDisplays.add(token, hw);//把顯示裝置物件儲存在mDisplays列表中
- }
- }
所有顯示裝置的輸出都要通過HWComposer物件完成,因此上面這段程式碼先呼叫了HWComposer的isConnected來檢查顯示裝置是否已連線,只有和顯示裝置連線的DisplayDevice物件才會被建立出來。即使沒有任何物理顯示裝置被檢測到,SurfaceFlinger都需要一個DisplayDevice物件才能正常工作,因此,DISPLAY_PRIMARY型別的DisplayDevice物件總是會被建立出來。
createBuiltinDisplayLocked函式就是為顯示裝置物件建立一個BBinder型別的Token而已。
- void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {
- ALOGW_IF(mBuiltinDisplays[type],
- "Overwriting display token for display type %d", type);
- mBuiltinDisplays[type] = new BBinder();
- DisplayDeviceState info(type);
- // All non-virtual displays are currently considered secure.
- info.isSecure = true;
- mCurrentState.displays.add(mBuiltinDisplays[type], info);
- }
然後會呼叫createBufferQueue函式建立一個producer和consumer,這個之前分析過。然後又建立了一個FramebufferSurface物件。這裡我們看到在新建FramebufferSurface物件時把consumer引數傳入了代表是一個消費者。而在DisplayDevice的建構函式中,會建立一個Surface物件傳遞給底層的OpenGL ES使用,而這個Surface是一個生產者。在OpenGl ES中合成好了影象之後會將影象資料寫到Surface物件中,這將觸發consumer物件的onFrameAvailable函式被呼叫:
這就是Surface資料好了就通知消費者來拿資料做顯示用,在onFrameAvailable函式彙總,通過nextBuffer獲得影象資料,然後呼叫HWComposer物件mHwc的fbPost函式輸出。
- void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
- sp<GraphicBuffer> buf;
- sp<Fence> acquireFence;
- status_t err = nextBuffer(buf, acquireFence);
- if (err != NO_ERROR) {
- ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",
- strerror(-err), err);
- return;
- }
- err = mHwc.fbPost(mDisplayType, acquireFence, buf);
- if (err != NO_ERROR) {
- ALOGE("error posting framebuffer: %d", err);
- }
- }
fbPost函式最後通過呼叫Gralloc模組的post函式來輸出影象。
我們再來看看DisplayDevice的建構函式
- DisplayDevice::DisplayDevice(
- const sp<SurfaceFlinger>& flinger,
- DisplayType type,
- int32_t hwcId,
- int format,
- bool isSecure,
- const wp<IBinder>& displayToken,
- const sp<DisplaySurface>& displaySurface,
- const sp<IGraphicBufferProducer>& producer,
- EGLConfig config)
- : lastCompositionHadVisibleLayers(false),
- mFlinger(flinger),
- mType(type), mHwcDisplayId(hwcId),
- mDisplayToken(displayToken),
- mDisplaySurface(displaySurface),
- mDisplay(EGL_NO_DISPLAY),
- mSurface(EGL_NO_SURFACE),
- mDisplayWidth(), mDisplayHeight(), mFormat(),
- mFlags(),
- mPageFlipCount(),
- mIsSecure(isSecure),
- mSecureLayerVisible(false),
- mLayerStack(NO_LAYER_STACK),
- mOrientation(),
- mPowerMode(HWC_POWER_MODE_OFF),
- mActiveConfig(0)
- {
- mNativeWindow = new Surface(producer, false);//建立Surface物件
- ANativeWindow* const window = mNativeWindow.get();
- /*
- * Create our display's surface
- */
- EGLSurface surface;
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (config == EGL_NO_CONFIG) {
- config = RenderEngine::chooseEglConfig(display, format);
- }
- surface = eglCreateWindowSurface(display, config, window, NULL);
- eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth);
- eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);
- // Make sure that composition can never be stalled by a virtual display
- // consumer that isn't processing buffers fast enough. We have to do this
- // in two places:
- // * Here, in case the display is composed entirely by HWC.
- // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
- // window's swap interval in eglMakeCurrent, so they'll override the
- // interval we set here.
- if (mType >= DisplayDevice::DISPLAY_VIRTUAL)//虛擬裝置不支援影象合成
- window->setSwapInterval(window, 0);
- mConfig = config;
- mDisplay = display;
- mSurface = surface;
- mFormat = format;
- mPageFlipCount = 0;
- mViewport.makeInvalid();
- mFrame.makeInvalid();
- // virtual displays are always considered enabled 虛擬裝置螢幕認為是不關閉的
- mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ?
- HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
- // Name the display. The name will be replaced shortly if the display
- // was created with createDisplay().
- switch (mType) {//顯示裝置名稱
- case DISPLAY_PRIMARY:
- mDisplayName = "Built-in Screen";
- break;
- case DISPLAY_EXTERNAL:
- mDisplayName = "HDMI Screen";
- break;
- default:
- mDisplayName = "Virtual Screen"; // e.g. Overlay #n
- break;
- }
- // initialize the display orientation transform.
- setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
- }
上面建構函式主要功能是建立了一個Surface物件mNativeWindow,同時用它作為引數建立EGLSurface物件,這個EGLSurface物件是OpenGL ES中繪圖需要的。
這樣,在DisplayDevice中就建立了一個通向Framebuffer的通道,只要向DisplayDevice的mSurface寫入資料。就會到消費者FrameBufferSurface的onFrameAvailable函式,然後到HWComposer在到Gralloc模組,最後輸出到顯示裝置。
swapBuffers函式將內部緩衝區的影象資料重新整理到顯示裝置的Framebuffer中,它通過呼叫eglSwapBuffers函式來完成緩衝區重新整理工作。但是注意呼叫swapBuffers輸出影象是在顯示裝置不支援硬體composer的情況下。
- void DisplayDevice::swapBuffers(HWComposer& hwc) const {
- // We need to call eglSwapBuffers() if:
- // (1) we don't have a hardware composer, or
- // (2) we did GLES composition this frame, and either
- // (a) we have framebuffer target support (not present on legacy
- // devices, where HWComposer::commit() handles things); or
- // (b) this is a virtual display
- if (hwc.initCheck() != NO_ERROR ||
- (hwc.hasGlesComposition(mHwcDisplayId) &&
- (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) {
- EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
- if (!success) {
- EGLint error = eglGetError();
- if (error == EGL_CONTEXT_LOST ||
- mType == DisplayDevice::DISPLAY_PRIMARY) {
- LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x",
- mDisplay, mSurface, error);
- } else {
- ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x",
- mDisplay, mSurface, error);
- }
- }
- }
- else if(hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL)
- {
- EGLBoolean success = eglSwapBuffersVIV(mDisplay, mSurface);
- if (!success) {
- EGLint error = eglGetError();
- ALOGE("eglSwapBuffersVIV(%p, %p) failed with 0x%08x",
- mDisplay, mSurface, error);
- }
- }
- status_t result = mDisplaySurface->advanceFrame();
- if (result != NO_ERROR) {
- ALOGE("[%s] failed pushing new frame to HWC: %d",
- mDisplayName.string(), result);
- }
- }
四、VSync訊號的分發過程
在之前的部落格分析過,當VSync訊號到來時會呼叫HWComposer類中的vsync函式
- void HWComposer::vsync(int disp, int64_t timestamp) {
- if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
- {
- Mutex::Autolock _l(mLock);
- // There have been reports of HWCs that signal several vsync events
- // with the same timestamp when turning the display off and on. This
- // is a bug in the HWC implementation, but filter the extra events
- // out here so they don't cause havoc downstream.
- if (timestamp == mLastHwVSync[disp]) {
- ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
- timestamp);
- return;
- }
- mLastHwVSync[disp] = timestamp;
- }
- char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
- ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
- mEventHandler.onVSyncReceived(disp, timestamp);
- }
- }
這個函式主要是呼叫了mEventHandler.onVSyncReceived函式,讓我們先來看下mEventHandler的構造,看HWComposer的建構函式,mEventHandler是傳入的引數handler。
- HWComposer::HWComposer(
- const sp<SurfaceFlinger>& flinger,
- EventHandler& handler)
- : mFlinger(flinger),
- mFbDev(0), mHwc(0), mNumDisplays(1),
- mCBContext(new cb_context),
- mEventHandler(handler),
- mDebugForceFakeVSync(false)
那麼我們就要看新建HWComposer的地方了,是在SurfaceFlinger的init函式中新建的,這handler就是SurfaceFlinger物件。
- mHwc = new HWComposer(this,
- *static_cast<HWComposer::EventHandler *>(this));
因此上面的mEventHandler.onVSyncReceived函式,就是呼叫了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);
- }
- }
4.1 DispSync類
上面函式我們主要看下DispSync的addResyncSample函式,看這個函式之前先看下DispSync的建構函式,在建構函式中啟動了DispSyncThread執行緒
- DispSync::DispSync() :
- mRefreshSkipCount(0),
- mThread(new DispSyncThread()) {
- mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
我們再來看addResyncSample函式,將VSync訊號的時間戳儲存大搜了陣列mResyncSamples中。然後呼叫了updateModelLocked函式繼續分發VSync訊號。
- 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主要顯示利用陣列mResyncSamples中的值計算mPeriod和mPhase這兩個時間值。然後最後呼叫了mThread的updateModel函式。mThread是DispSyncThread類。
- void DispSync::updateModelLocked() {
- if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
- ......
- //計算mPeriod和mPhase
- mThread->updateModel(mPeriod, mPhase);
- }
- }
我們來看下DispSyncThread的updateModel函式,這個函式只是儲存了引數,然後呼叫了Condition的signal喚醒執行緒。
- void updateModel(nsecs_t period, nsecs_t phase) {
- Mutex::Autolock lock(mMutex);
- mPeriod = period;
- mPhase = phase;
- mCond.signal();
- }
我們再來看DispSyncThread的threadLoop函式,主要這個函式比較計算時間來決定是否要傳送訊號。如果沒有訊號傳送就會在mCond等待,有訊號傳送前面會在updateModel中呼叫mCond的singal函式,這裡執行緒就喚醒了。gatherCallbackInvocationsLocked函式獲取本次VSync訊號的回撥函式列表,這些回撥函式是通過DispSync類的addEventListener函式加入的。接著就呼叫fireCallbackInvocations來依次呼叫列表中所有物件的onDispSyncEvent函式。
- virtual bool threadLoop() {
- ......
- while (true) {
- Vector<CallbackInvocation> callbackInvocations;
- nsecs_t targetTime = 0;
- { // Scope for lock
- ......
- if (now < targetTime) {
- err = mCond.waitRelative(mMutex, targetTime - now);
- ......
- }
- now = systemTime(SYSTEM_TIME_MONOTONIC);
- ......
- callbackInvocations = gatherCallbackInvocationsLocked(now);
- }
- if (callbackInvocations.size() > 0) {
- fireCallbackInvocations(callbackInvocations);
- }
- }
- return false;
- }
fireCallbackInvocations函式就是遍歷回撥列表呼叫其onDispSyncEvent函式。
- void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
- for (size_t i = 0; i < callbacks.size(); i++) {
- callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
- }
- }
4.2 EventThread和DispSync的關係
這裡我們先不往下分析DispSync遍歷呼叫回撥,我們先來看看EventThread的threadLoop函式,這個函式邏輯很簡單。呼叫waitForEvent來獲取事件,然後呼叫每個連線的postEvent來傳送Event。
- bool EventThread::threadLoop() {
- DisplayEventReceiver::Event event;
- Vector< sp<EventThread::Connection> > signalConnections;
- signalConnections = waitForEvent(&event);//獲取Event
- // dispatch events to listeners...
- const size_t count = signalConnections.size();
- for (size_t i=0 ; i<count ; i++) {
- const sp<Connection>& conn(signalConnections[i]);
- // now see if we still need to report this event
- status_t err = conn->postEvent(event);//傳送Event
- if (err == -EAGAIN || err == -EWOULDBLOCK) {
- // The destination doesn't accept events anymore, it's probably
- // full. For now, we just drop the events on the floor.
- // FIXME: Note that some events cannot be dropped and would have
- // to be re-sent later.
- // Right-now we don't have the ability to do this.
- ALOGW("EventThread: dropping event (%08x) for connection %p",
- event.header.type, conn.get());
- } else if (err < 0) {
- // handle any other error on the pipe as fatal. the only
- // reasonable thing to do is to clean-up this connection.
- // The most common error we'll get here is -EPIPE.
- removeDisplayEventConnection(signalConnections[i]);
- }
- }
- return true;
- }
我們再來看下waitForEvent函式中下面程式碼段,timestamp為0表示沒有時間,waitForSync為true表示至少有一個客戶和EventThread建立了連線。這段程式碼一旦有客戶連線,就呼叫enableVSyncLocked接收DispSyncSource的VSync訊號。如果在接受訊號中,所有客戶都斷開了連線,則呼叫disableVSyncLocked函式停止接受DispSyncSource物件的訊號。
- // 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();
- }
我們先來看下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();
- }
我們先來看看mVSyncSource->setCallback函式。先要知道這個mVSyncSource是在SurfaceFlinger的init函式中。
- 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);
看到上面這段程式碼,我們知道這個mVsyncSource是DispSyncSource類,我們先來看起setCallback函式,就是把callback儲存起來
- virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
- Mutex::Autolock lock(mCallbackMutex);
- mCallback = callback;
- }
再來看setVSyncEnabled函式,這裡引數enable是true,就是呼叫了DispSync的addEventListenter。這裡就回到了上一小節了,這裡我們就在DispSync中註冊了回撥了
- 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;
- }
這樣回想上一節在fireCallbackInvocations中遍歷所有的回撥時,就呼叫了DispSyncSource類的onDispSyncEvent函式,而這個函式主要是呼叫了其成員變數mCallback的onVSyncEvent,這個mCallback就是之前在EventThread中的waitForEvent註冊的,就是EventThread自己。
- 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);
- }
- }
因此最後到了EventThread的onVsyncEvent函式,這個函式把資料放在mVSyncEvent陣列第一個,然後呼叫了Condition的broadcast函式。
- 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的threadLoop函式中呼叫waitForEvent會阻塞,當這裡呼叫Condition的broadcast之後,waitForEvent就喚醒,並且得到了mVsynEvent中的資料。緊接著就是在EventThread中的threadLoop呼叫conn->postEvent來傳送Event。這裡是通過BitTube物件中的socket傳送到MessageQueue中。這個我們在第二節中分析過了。
4.3 MessageQueue分發VSync訊號
我們來回顧下,在MessageQueue中有下面這個函式。這樣當EventThread通過BitTube傳送資料的話,pollOnce會喚醒epoll_wait然後就到這個cb_eventReceiver這個回撥函式
- void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
- {
- mEventThread = eventThread;
- mEvents = eventThread->createEventConnection();
- mEventTube = mEvents->getDataChannel();
- mLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT,
- MessageQueue::cb_eventReceiver, this);
- }
cb_eventReceiver就是呼叫了eventReceiver函式。
- int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
- MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
- return queue->eventReceiver(fd, events);
- }
- int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
- ssize_t n;
- DisplayEventReceiver::Event buffer[8];
- while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
- for (int i=0 ; i<n ; i++) {
- if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- #if INVALIDATE_ON_VSYNC
- mHandler->dispatchInvalidate();
- #else
- mHandler->dispatchRefresh();
- #endif
- break;
- }
- }
- }
- return 1;
- }
這裡我們支援VSync訊號就會呼叫mHandler的dispatchRefresh函式。
- void MessageQueue::Handler::dispatchRefresh() {
- if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
- mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
- }
- }
而在Hander的處理中,最終是呼叫了SurfaceFlinger的onMessageReceived函式
- case REFRESH:
- android_atomic_and(~eventMaskRefresh, &mEventMask);
- mQueue.mFlinger->onMessageReceived(message.what);
- break;
而在SurfaceFlinger的onMessageReceived函式最終會呼叫了handleMessageRefresh函式。
- void SurfaceFlinger::onMessageReceived(int32_t what) {
- ATRACE_CALL();
- switch (what) {
- ......
- case MessageQueue::REFRESH: {
- handleMessageRefresh();
- break;
- }
- }
- }
handleMessageRefresh函式負責重新整理系統的顯示。這樣我們就分析了從底層傳送VSync訊號最終到達SurfaceFlinger的handleMessageRefresh函式。
4.4 VSync訊號分發總結
我們回顧下整個流程,VSync訊號從底層產生後,經過幾個函式,儲存到了SurfaceFlinger的mPrimaryDispSync變數(DisySync類)的陣列中,這樣設計的目的讓底層的呼叫盡快結束,否則會耽擱下次VSync訊號的傳送。然後在mPrimaryDispSync變數關聯的執行緒開始分發陣列中的VSync訊號,分發的過程也呼叫了幾個回撥函式,最終結果是放在EventThread物件的陣列中。EventThread是轉發VSync訊號的中心。不但會把VSync訊號發給SurfaceFlinger,還會把訊號傳送到使用者程式中去。EventThread的工作比較重,因此SurfaceFlinger中使用了兩個EventThread物件來轉發VSync訊號。確保能及時轉發。SurfaceFlinger中的MessageQueue收到Event後,會將Event轉化成訊息傳送,這樣最終就能在主執行緒呼叫SurfaceFlinger的函式處理VSync訊號了。
相關文章
- Android 12(S) 影像顯示系統 - SurfaceFlinger 之 VSync - 中篇(十七)Android
- Android 12(S) 影像顯示系統 - SurfaceFlinger之VSync-上篇(十六)Android
- Android 12(S) 影像顯示系統 - SurfaceFlinger GPU合成/CLIENT合成方式 - 隨筆1AndroidGPUclient
- Android 12(S) 圖形顯示系統 - 應用建立和SurfaceFlinger的溝通橋樑(三)Android
- Android 12(S) 圖形顯示系統 - SurfaceFlinger的啟動和訊息佇列處理機制(四)Android佇列
- Android 12(S) 圖形顯示系統 - createSurface的流程(五)Android
- Android系統耳機圖示顯示Android
- Android 12(S) 圖形顯示系統 - 簡述Allocator/Mapper HAL服務的獲取過程(十五)AndroidAPP
- 會議同屏顯示系統
- 待機顯示服務協議及隱私政策協議
- win10系統顯示桌面圖示的方法Win10
- iPhone手機出現無服務怎麼辦?如何解決顯示無服務iPhone
- uname命令顯示系統資訊?linux系統運維命令Linux運維
- abp(net core)+easyui+efcore倉儲系統——建立應用服務(五)UI
- linux系統lcd顯示jpg格式圖片Linux
- 讓windows系統顯示隱藏檔案Windows
- Linux下注冊系統服務Linux
- 把程式做成系統服務
- Win10系統怎麼在工作管理員顯示顯示卡溫度Win10
- win10系統下顯示卡設定在哪 win10系統如何開啟顯示卡設定Win10
- Win10系統如何建立顯示桌面圖示_win10怎麼新增顯示桌面Win10
- mac系統桌面怎麼顯示CD圖示等裝置?Mac
- 直播系統開發,實現在進度條中顯示文字顯示進度
- Linux基礎命令---tload顯示系統負載Linux負載
- Android顯示子系統相關基礎概念Android
- Android 12(S) 圖形顯示系統 - 開篇Android
- win10啟動windows服務顯示服務沒有響應控制功能怎麼解決Win10Windows
- linux系統 Apache服務配置教程。LinuxApache
- 開放式服務管理系統
- Linux系統安裝Redis服務LinuxRedis
- 【系統設計】鄰近服務
- linux系統服務(systemctl)的使用Linux
- win10系統125%顯示不清晰怎麼調_win10系統125%顯示不清晰的修復方法Win10
- win10系統amd顯示卡如何切換到獨顯Win10
- BIOS系統服務 —— 直接磁碟服務(int 0x13)iOS
- 客戶服務CRM系統,提供優質客戶服務
- Win10系統下雙顯示卡切換到獨立顯示卡的方法Win10
- SurfaceFlinger 統計平均幀率中的疑惑