struct State {
LayerVector layersSortedByZ;
DefaultKeyedVector< wp
};
layersSortedByZ儲存的是排序過的所有Layer物件, displays則是所有Display的State. layersSortedByZ是先以LayerStack排序(由小到大), 如果LayerStack相同, 再以Layer的Z做排序(由小到大).
State的變化由client的request開始, client必須透過ISurfaceComposerClient的interface與SF溝通. client可以是NDK app, 也可以是Java app. client在下command時是這樣子的, 它必須將request包在openGlobalTransaction與closeGlobalTransaction裡, 中間的每一個set function會更新ComposerState或DisplayState, 然後統一在closeGlobalTransaction時全部交給SurfaceFlinger::setTransactionState. 所以, 嚴格的來說, SurfaceFlinger::setTransactionState是SF對client的唯一interface.
State的變化由client的request開始, client必須透過ISurfaceComposerClient的interface與SF溝通. client可以是NDK app, 也可以是Java app. client在下command時是這樣子的, 它必須將request包在openGlobalTransaction與closeGlobalTransaction裡, 中間的每一個set function會更新ComposerState或DisplayState, 然後統一在closeGlobalTransaction時全部交給SurfaceFlinger::setTransactionState. 所以, 嚴格的來說, SurfaceFlinger::setTransactionState是SF對client的唯一interface.
SurfaceComposerClient::openGlobalTransaction();
surfaceControl->setXXX(...);
surfaceControl->setYYY(...);
SurfaceComposerClient::closeGlobalTransaction();
這裡有一個Threading Model要注意一下. SurfaceFlinger::setTransactionState是run在client所使用的binder thread. 讓我多解釋一下這句話. client與SF通常是分屬不同Process, 當client呼叫ISurfaceComposerClient的function時, 它是執行在SF的process裡, 但是這是透過binder做到的, SF裡有binder thread pool, 所以當client呼叫ISurfaceComposerClient時, binder會從SF的binder thread pool取得一個thread來執行, client本身的thread這個時候通常是被block的. 所以, SurfaceFlinger::setTransactionState是執行在SF的binder thread, 而SF本身state的update, 以至於後續的動作是在SF的main thread裡執行, 而main thread通常是在VSYNC-sf開始的時候才執行, 下面這張圖或許可以讓你比較清楚一點.
在VSYNC-sf發生時, SF的main thread會讀取內部的Layer與DisplayDeviceState物件, 為了避免SF在讀的時候, client正在更新state, SurfaceFlinger::mStateLock會用來避免這件事.
SurfaceFlinger裡有好幾個thread, 其中一個是main thread, 也就是SurfaceFlinger主要執行的thread, 另外有兩個VSYNC thread, 一個用來產生VSYNC-sf, 另一個產生VSYNC-app, 在這裡我們主要著重在VSYNC-sf, 簡單稱為VSYNC-sf thread. VSYNC-sf thread的requestNextVSync必須被呼叫, VSYNC-sf thread才會在VSYNC-sf發生時, queue一個INVALIDATE的message給main thread, main thread才會被叫醒, SF的state才會更新, 反應在使用者面前.
VSYNC-sf的requestNextVsync是在MessageQueue::invalidate()中被呼叫到的, Client (SF Client, 透過ISurfaceComposerClient)或main thread是使用setTransactionFlags()-->signalTransaction()-->MessageQueue::invalidate()這條路徑.
Double State Tracking
SurfaceFlinger有兩個State物件, 分別是mCurrentState與mDrawingState. mCurrentState指的是新要求的State, 但還沒反應在使用者面前, mDrawingState則是指目前已經反應在使用者面前. 但是在某個時間點(commitTransaction), mCurrentState的內容會被複製到mDrawingState. 利用這兩個State, 就可以知道有什麼需要更新. 除了SF本身外, 每一個Layer也有mCurrentState與mDrawingState, 具有相同的意義.surfaceControl->setXXX(...);
surfaceControl->setYYY(...);
SurfaceComposerClient::closeGlobalTransaction();
這裡有一個Threading Model要注意一下. SurfaceFlinger::setTransactionState是run在client所使用的binder thread. 讓我多解釋一下這句話. client與SF通常是分屬不同Process, 當client呼叫ISurfaceComposerClient的function時, 它是執行在SF的process裡, 但是這是透過binder做到的, SF裡有binder thread pool, 所以當client呼叫ISurfaceComposerClient時, binder會從SF的binder thread pool取得一個thread來執行, client本身的thread這個時候通常是被block的. 所以, SurfaceFlinger::setTransactionState是執行在SF的binder thread, 而SF本身state的update, 以至於後續的動作是在SF的main thread裡執行, 而main thread通常是在VSYNC-sf開始的時候才執行, 下面這張圖或許可以讓你比較清楚一點.
在VSYNC-sf發生時, SF的main thread會讀取內部的Layer與DisplayDeviceState物件, 為了避免SF在讀的時候, client正在更新state, SurfaceFlinger::mStateLock會用來避免這件事.
SurfaceFlinger裡有好幾個thread, 其中一個是main thread, 也就是SurfaceFlinger主要執行的thread, 另外有兩個VSYNC thread, 一個用來產生VSYNC-sf, 另一個產生VSYNC-app, 在這裡我們主要著重在VSYNC-sf, 簡單稱為VSYNC-sf thread. VSYNC-sf thread的requestNextVSync必須被呼叫, VSYNC-sf thread才會在VSYNC-sf發生時, queue一個INVALIDATE的message給main thread, main thread才會被叫醒, SF的state才會更新, 反應在使用者面前.
VSYNC-sf的requestNextVsync是在MessageQueue::invalidate()中被呼叫到的, Client (SF Client, 透過ISurfaceComposerClient)或main thread是使用setTransactionFlags()-->signalTransaction()-->MessageQueue::invalidate()這條路徑.
Double State Tracking
Layer
Layer代表Activity裡一個ViewRootImpl的畫面, 每一個ViewRootImp都有相對應的Layer, Android的畫面就是由多個Layer所組合而成, 這些Layer有前後關係(用Z值作區分), 因此, 有些Layer會蓋在某些Layer之上, 有些Layer是透明或半透明, SF將這些Layer組成一個畫面顯示在使用者面前.
當一個Layer產生時, 它會產生一個handle, 這個Handle是要傳回給client, 當client要調整這個Layer屬性時, 需要將這個handle傳到SF, SF才有辦法找到相對的Layer物件. ($TOP/frameworks/base/core/java/android/view/SurfaceControl.java). handle是一個簡單BBinder物件
當這個handle被destroy後, LayerCleaner::~LayerCleaner()會被執行, 再去呼叫SurfaceFlinger::onLayerDestroyed()做後續處理.
每一個ViewRootImp的畫面都是由client所繪製的, SF只是負責將它組合顯示在使用者面前, 因此, 一個Layer產生後第一次被使用時, SF會產生一個BufferQueue, Producer是MonitorProducer物件, Consumer則是SurfaceFlingerConsumer物件, Producer的interface會傳回給client, client可以利用producer interface將畫好的GraphicBuffer放入BQ, 然後由SF使用.
void Layer::onFirstRef() {
...
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp
sp
BufferQueue::createBufferQueue(&producer, &consumer);
mProducer = new MonitoredProducer(producer, mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
....
}
MonitoredProducer
MonitoredProducer是一個很簡單的Pass-Through class, 所有的Producer interface都是直接呼叫createBufferQueue()所產生的producer object. 它有一個cleanup的功能, 當MonitoredProducer被destroy時, 它會post一個message給SF去做clean的工作, 其實只是將Producer從SurfaceFlinger::mGraphicBufferProducerList中移除而已.SurfaceFlingerConsumer
SurfaceFlingerConsumer是GLConsumer的subclass, 這個consumer的用途可以將MonitoredProducer所放入的GraphicBuffer取出當做Texture使用, 當它的updateTexImage()被呼叫時, 它會從BQ裡取出Buffer供SurfaceFlinger::RenderEngine使用. 一般而言, 當Producer將Buffer放入BQ時, Consumer的onFrameAvailable()會被執行, 但是在上面的code裡有一行
mSurfaceFlingerConsumer->setContentsChangedListener(this);
這一行會使得Layer::onFrameAvailable()被執行, 而不是SurfaceFlingerConsumer::onFrameAvailable. 當Layer::onFrameAvailable()被執行時, 會對Layer::mQueuedFrames累加, 這個變數代表這個Layer有幾個畫面已經更新, 但還沒被SF處理.
void Layer::onFrameAvailable() {
android_atomic_inc(&mQueuedFrames);
mFlinger->signalLayerUpdate();
}
ComposerState
ComposerState包含client的pointer與一layer_state_t的結構. layer_state_t::surface存的是Layer的handle, 也就是上面提到, 當Layer被create時, 它會產生一個Handle物件傳回給client. Client要對這個Layer進行操作必須將這個handle傳回SF, SF會利用Client::getLayerUser()從client所有的layer裡找出來. 一個client可以有多個layer, 最常見的case就是一個Activity叫出Dialog, 這個Dialog也是一個Layer, 因此這個client就有2個layer.
struct ComposerState {
sp
layer_state_t state;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
};
Display
在SurfaceFlinger裡, Display可以分成兩種, 一種是Physical Display, 也就是一個實體的Monitor或Panel接在機器上, 另一種是Virtual Display, 像是WifiDisplay或Chromecast, 它不是一個實體的Monitor連接著你的機器.
SurfaceFlinger利用幾個data structure來管理Display.
SurfaceFlinger::mBuiltinDisplays
這是一個table, 每個entry都是一個BBinder物件, 每一個BBinder代表一個Physical Display的Token, Virtual Display的Token不會存在這裡.
SurfaceFlinger::State::displays
這是一個mapping table, 利用Display的Token, 可以取得該Display的DisplayDeviceState, 所有的Display的DisplayDeviceState (包含Virtual Display)都可以從這裡取得. DisplayDeviceState記錄該Display的狀態, 它的內容是根據client傳進來的DisplayState而設定的.
SurfaceFlinger::mDisplays
這也是一個mapping table, 利用Display的Token, 可以取得該Display的DisplayDevice物件.
在SF裡, 每一個Display, 不管是Physical或Virtual都有一個Token, 可以把它想成是個ID用來辨識不同的Display. Physical Display的Token是BBinder class, Virtual Display則是DisplayToken class. DisplayToken是BBinder的subclass, 所以它也可以以BBinder的形態儲存.
Token只是一個類似ID的作用, 真正在記錄或處理Display的則是一個叫DisplayDevice的class. SurfaceFlinger::mDisplays記錄著每一個Display(包含Virtual)的DisplayDevice物件, 利用Display的Token可以找到相對應的DisplayDevice.
DisplayState
DisplayState是client跟SF溝通的一個結構, SF會將這個結構的內容反應在每個Display的DisplayDeviceState裡, 當SF main thread執行時, 它會比較mCurrentState與mDrawingState來決定是否有display hot plug/unplug發生, 也會更新一些屬性, 像是width, height, projection matrix等等.
DisplayDevice
不管前面的Flow如何, SF最終要將相關的State更新到DisplayDevice物件裡. 針對每一個Display, 除了會有一個DisplayDevice外, SF還會為每一個Display產生一個BufferQueue. DisplayDevice物件在被create時, 會利用eglCreateWindowSurface產生一個EGLSurface當作BQ的Producer. Physical與Virtual Display在這方面有點不同, 請見下圖.
Producer是EGLSurface, 因為它主要是用在GLES composition. EGLContext是使用SurfaceFlinger的RenderEngine.
DisplayDevice比較像是一個PlaceHolder放Display相關的資料, SF在稍後更新Layer或HWComposer的狀態時, 會用到裡面的資料.
Wrap Up
在看SF的code, 最好能掌握一個原則, SF的main thread才是主導State的關鍵, 而且它只有在VSYNC-sf發生時才會被叫醒, 其餘時間它是在sleep的狀態. 另外, client主要是透過setTransactionState將client state (ComposerState && DisplayState)轉換成SF內部的state (Layer && DisplayDeviceState). SF main thread只從內部的state來比較是否有任何新的request, 然後才去處理. 它的流程大概是像下面這個樣子
- Client (binder thread)呼叫setTransactionState傳入ComposerState與DisplayState, setTransactionState會做幾件事
- 利用setClientStateLocked()與setDisplayStateLocked()將ComposerState與DisplayState反應在Layer與DisplayDeviceState裡.
- 利用setTransactionFlag將SF main thread叫醒.
- 如果client要求synchronous mode, setTransactionState就會一直等到main thread將state處理完才return.因此, client使用的binder thread會被block住直到main thread執行完handleTranslactionLocked.
- SF main thread被叫醒後, 會利用handleTransactionLocked()檢查各個Layer與DisplayDeviceState. 接下來我們會看handleTransactionLocked()
handleTransactionLocked()
這個function看起來似乎比較長, 但實際上它的邏輯不複雜, 我們可以將它分成幾個部份來看
Layer Update
檢查每一個Layer是否有任何的更新, 如果有, 就利用Layer::doTransaction()對該Layer做更新.
Layer::doTransaction()跟handleTransactionLocked()的意義是一樣的, 差別在於doTranaction是對Layer做state的檢查, 但handleTransactionLocked()是針對整個SF做state的檢查. 把它想成一層一層的管理, 就會比較容易理解.
在這裡會比較mCurrentState與mDrawingState裡的displays, 從這兩個State裡display的不同, 可以得知是否有hot plug/unplug的發生.
- 如果一個Display在mDrawingState.displays, 但不在mCurrentState.displays, 代表該Display發生unplug. 需要呼叫EventThread::onHotplugReceived()通知其它component有display unplug.並將DisplayDevice物件從SurfaceFlinger::mDisplays中移除.
- 如果一個Display在mCurrentState.displays, 但不在mDrawingState.displays裡, 代表該Display發生hot plug. 除了要利用EventThread::onHotplugReceived()通知其它componenet外, 還必須產生一個新DisplayDevice放到SurfaceFlinger::mDisplays裡. 而且必須為這個Display產生BufferQueue, 並更新DisplayDevice的一些屬性, 像是layerStack, projection matrix等.
- 如果一個Display同時出現在mCurrentState.displays與mDrawingState.displays, 表示這個Display可能有些屬性改變, 像LayerStack, projection matrix等.
Dirty Region Update
由於Activity可能會結束, 因此Layer也會被刪除, 這有可能會影響到畫面上可看見的區域. 透過mCurrentState與mDrawingState的比較, 可以知道哪些Layer被刪除了, 這些被刪除的Layer的顯示區域必須設成Dirty, 要重畫.
上面紅色區域就是用來計算被移掉的Layer的可見區域, 然後交給invalidateLayerStack()來更DisplayDevice裡的dirty region. 如果我們看一下invalidateLayerStack(), 它會檢查被移除Layer的LayerStack是否與DisplayDevice的LayerStack相同, 才會更新DisplayDevice的dirty region. LayerStack是用來決定一個Layer是否要在一個Display上顯示出來. 我們會再另外討論這個東西.
在handleTransactionLocked()的最後會有一個commitTransaction()的動作, 這個很重要, 因為它會將mCurrentState的內容複製到mDrawingState裡, 這代表在這之後, 如果要知道哪些State有更新, 要去參考mDrawingState, 而不是mCurrentState. 因為從這之後, mCurrentState就會繼續接收client新的state update.
沒有留言:
張貼留言