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不為空,且layer的compositionType == 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的緩衝區管理,我們在前幾個小節已經分析過了,大家可以結合這裡的場景再看一遍。