1. 程式人生 > >GUI系統之SurfaceFlinger(18)postFramebuffer

GUI系統之SurfaceFlinger(18)postFramebuffer

文章都是通過閱讀原始碼分析出來的,還在不斷完善與改進中,其中難免有些地方理解得不對,歡迎大家批評指正。
轉載請註明:From LXS. http://blog.csdn.net/uiop78uiop78/

GUI系統之SurfaceFlinger章節目錄:

blog.csdn.net/uiop78uiop78/article/details/8954508

在多緩衝區機制中,只有把顯示資料寫入framebuffer才能真正在物理螢幕上顯示。前面幾個小節的輸出都是backbuffers,我們還需要最後一步——postFramebuffer。

void SurfaceFlinger::postFramebuffer()

{…   

    const DisplayHardware&hw(graphicPlane(0).displayHardware());

    …

    hw.flip(mSwapRegion);//交換前後臺buffer

    size_t numLayers =mVisibleLayersSortedByZ.size();

    for (size_t i = 0; i <numLayers; i++) {

       mVisibleLayersSortedByZ[i]->onLayerDisplayed();

    }

    …

}

先從opengl本地視窗的角度來想一下:

Ø  queueBuffer

一旦“生產者”完成生產後,它需要把當前的buffer重新入隊,以使“消費者”可以做接下來的處理

Ø  dequeueBuffer

為了“生產者”可以繼續下一輪的工作,它會重新deque

基本的思路就是這樣子,不過Android系統將一些步驟封裝到了DisplayHardware中,我們稍後會看到。

DisplayHardware::flip完成後,分別通知各可見Layer它們的內容已經顯示出來了。

void DisplayHardware::flip(const Region& dirty) const

{…

    mPageFlipCount++;//flip計數

    if (mHwc->initCheck()== NO_ERROR) {

        mHwc->commit();

    } else {

        eglSwapBuffers(dpy, surface);

    }

    …

}

分為兩條路徑:

(1)commit

成員變數mHwc是在DisplayHardware::init中生成的一個HWComposer物件。只要HWC_HARDWARE_MODULE_ID模組可以正常載入,且hwc_open能開啟hwc_composer_device裝置,那麼initCheck()就返回NO_ERROR,否則就是NO_INIT

此時我們通過HWComposer::commit來執行flip,這個函式直接呼叫如下硬體介面:

mHwc->set(mHwc,mDpy, mSur, mList);

set()和後面的eglSwapBuffers是基本等價的,原型如下:

int (*set)(struct hwc_composer_device *dev,hwc_display_t dpy,

hwc_surface_t sur,hwc_layer_list_t* list);

其中最後一個list必須與最近一次的prepare()所用列表完全一致。假如list為空或者列表數量為0的話,說明SurfaceFlinger已經利用OpenGL ES做了composition,此時set就和eglSwapBuffers一樣。當list不為空,且layercompositionType == HWC_OVERLAY,那麼HWComposer需要進行硬體合成。

如果成功執行的話,set返回0,否則就是HWC_EGL_ERROR。可以通過eglGetError()來獲得具體的error。感興趣的讀者可以自己挑選一個具體的平臺實現來分析,比如三星的crespo(路徑是/device/Samsung/crespo/libhwcomposer)

(2)eglSwapBuffers

libagl為例,這個函式又呼叫瞭如下的swapBuffers

/*frameworks/native/opengl/libagl/Egl.cpp*/

EGLBoolean egl_window_surface_v2_t::swapBuffers()

{…

    nativeWindow->queueBuffer(nativeWindow, buffer);

    …

    // dequeue一個新的buffer

    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {

       …

} else {

        returnsetError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);

    }

    return EGL_TRUE;

}

這和我們一開始的推測是一致的——通過queueBuffer來入隊,然後通過dequeueBuffer重新申請一個buffer以用於下一輪的重新整理。關於SurfaceFlinger中所使用的這一OpenGL本地視窗,即FramebufferNativeWindow的緩衝區管理,我們在前幾個小節已經分析過了,大家可以結合這裡的場景再看一遍。