SurfaceFlinger繼承了Thread類,自然也繼承了Thread類的threadLoop方法,SurfaceFlinger背景工作執行緒的主代碼都在threadLoop()方法中。背景工作執行緒啟動後,基類Thread會迴圈地調用threadLoop方法,SurfaceFlinger的threadLoop()主要是要完成系統中各個Layer(Surface)進行混合(compose),然後不停地把一幀幀混合好的映像資料傳送到顯示裝置中。
threadLoop的流程
圖一 threadLoop流程
1. handleConsoleEvents
handleConsoleEvent目前沒有深入瞭解,貌似只是處理顯示裝置進入休眠狀態或者從休眠中喚醒時,改變SufaceFlinger的狀態,然後threadLoop的後續流程會根據相應的狀態來決定是否繼續給顯示裝置傳送顯示資料。
2. handleTransaction
因為Layer的混合是線上程中進行的,而混合的過程中,應用程式或者系統可能會改變Layer的狀態,例如旋轉螢幕、增加或刪除Layer、某個Layer可見或不可見,為了使這些變動不會破壞當前進行中的混合動作,SurfaceFlinger維護著兩個Layer列表:
- mCurrentState.layersSortedByZ ---- 當前系統最新的Layer列表
- mDrawingState.layersSortedByZ ---- 本次混合操作使用的Layer列表
handleTransaction就是根據Layer列表的這些狀態的變化,計算是否有可見地區內需要更新,並設定狀態變數mVisibleRegionsDirty,然後把mCurrentState賦值給mDrawingState,最後釋放已經被丟棄(ditch)的Layer
- 上一次混合過程中,可能應用程式釋放了一個Layer,可是mDrawingState正在使用,不能馬上銷毀,所以要等到本次混合前才能做出銷毀的動作。
- 如果Layer的大小有變化並且可見,Layer的handleTransaction將會重新分配緩衝區,並且凍結SurfaceFlinger後續的混合操作,也就是螢幕的內容本次將不會重新整理,直到下一個迴圈的handlePageFlip階段才解除凍結。
3. handlePageFlip
該階段會遍曆各個Layer,在每個Layer中,取得並鎖住該Layer的frontBuffer,然後利用frontBuffer中的映像資料產生該Layer的2D貼圖(Texture),並且計算更新地區,為後續的混合操作做準備。
圖二 handlePageFlip處理流程
Layer的lockPageFlip()首先通過SharedBufferServer類的成員變數lcblk,調用retireAndLock取得該Layer當前可用的frontBuffer,然後通過reloadTexture方法產生openGL ES的紋理貼圖,最後通過unlockPageFlip完成更新地區的Layer座標到螢幕座標的變換。
handleRepaint
handleRepaint真正實現Layer混合的階段,是handleRepaint的處理流程:
圖三 handleRepaint 的處理流程
handleRepaint首先重設了openGL的觀察矩陣,然後遍曆mDrawingState.layersSortedByZ 中的Layer列表,調用每個Layer的onDraw方法,在onDraw方法中,會調用drawWithOpenGL()方法,將在handlePageFlip階段產生的貼圖混合到OpenGL的主表面,最後handleRepaint把需要重新整理的地區清除。
unlockClients
unlockClients只是遍曆各個Layer並調用各個Layer的finishPageFlip方法。finishPageFlip會進一步調用SharedBufferServer的unlock()方法:(關於SharedBufferSever,請參考本人以下博文的SharedClient 和 SharedBufferStack一節)
void Layer::finishPageFlip()<br />{<br /> status_t err = lcblk->unlock( mFrontBufferIndex );<br /> LOGE_IF(err!=NO_ERROR,<br /> "layer %p, buffer=%d wasn't locked!",<br /> this, mFrontBufferIndex);<br />}<br />
lcblk->unlock( mFrontBufferIndex )會把Layer的frontBuffer解除鎖定。
postFramebuffer
進入postFramebuffer階段,OpenGL主表面已經準備好了混合完成的映像資料,postFramebuffer只是簡單地調用hw.flip(),hw.flip()進一步調用了eglSwapBuffers完成主表面的切換,這樣螢幕上的映像就會更新為新的資料。