在我工作的平台上,HDMI output ,每次 vsync 發生時 surfaceflinger 收到的 message 是 MessageQueue::INVALIDATE。然後surfaceflinger 會執行下面 function ,
handleMessageTransaction();
handleMessageInvalidate();
signalRefresh();
這篇主要先分析 handleMessageTransaction()。而這個 function 全文在 4.3 中如下
void SurfaceFlinger::handleMessageTransaction() {
uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
if (transactionFlags) {
handleTransaction(transactionFlags);
}
}
他會先透過 peekTransactionFlags(eTransactionMask),來窺視 mTransactionFlags 是否非零,如果是才會進入 handleTransaction(transactionFlags)。mTransactionFlags 是 surfaceflinger 中的一個 member ,當有某個 surface 狀態有改變或createSurface、 removeSurface、addLayer 等等的行為發生時都會透過 SurfaceFlinger::setTransactionFlags() 設定這個 flag 。目前有三個 bit 可被設置,分別如下
enum {
eTransactionNeeded = 0x01, (二進位表示0001)
eTraversalNeeded = 0x02, (二進位表示0010)
eDisplayTransactionNeeded = 0x04, (二進位表示0100)
eTransactionMask = 0x07 (二進位表示0111)
};
其中個別代表什麼還不是很清楚,在 surfaceflinger 搜尋 setTransactionFlags 看到 eTransactionNeeded 會在 createLayer、removeLaye 中被設置。eDisplayTransactionNeeded 則在 createDisplay() 跟 onHotplugReceived () 中被設置,。eTraversalNeeded 則是在 surfaceFlinger 裡面我搜尋不到,應該是由別的地方去設置,將來有看到再補。
========================================================================
回到 handleMessageTransaction 中,上面的任何一個情況有發生,才會呼叫 handleTransaction 。
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
// Here we're guaranteed that some transaction flags are set
// so we can call handleTransactionLocked() unconditionally.
// We call getTransactionFlags(), which will also clear the flags,
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
}
這個很短沒什麼特別需要解釋的,其中 invalidateHwcGeometry 這個 function 只是執行 mHwWorkListDirty = true,實際上做什麼目前還不清楚,之後有看到再補。
所以接下來就是進入 handleTransactionLocked()中。
========================================================================
handleTransactionLocked 比較長,主要就是去檢視上面提到的 mTransactionFlags 來執行對應的工作。還是照著順序來吧。
首先,檢查 eTraversalNeeded 是否有被拉起來,有的話,顧名思義 traversal 所有 layer。
if (transactionFlags & eTraversalNeeded) {
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
}
}
layer->getTransactionFlags(eTransactionNeeded) 會檢查 layer 類別中的成員 mTransactionFlags 的
eTransactionNeeded 是否被設置。注意這裡的 mTransactionFlags 只給每個 layer 自己用 ,surfaceflinger 中也有一個名稱一樣的(也就是上面提的),不要搞混了。如果目前掃到的 layer 的
eTransactionNeeded 有被設置,就執行
layer->doTransaction。
接著分析 Layer 中的 doTransaction 在做什麼。首先
const Layer::State& front(drawingState());
const Layer::State& temp(currentState());
const bool sizeChanged = (temp.requested.w != front.requested.w) ||
(temp.requested.h != front.requested.h);
if (sizeChanged) {
// record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
mSurfaceFlingerConsumer->setDefaultBufferSize(
temp.requested.w, temp.requested.h);
}
drawingState 會回傳 Layer 中的 mDrawingState ,代表的是 " 上一次 drawing " 的 layer 狀態;而 currentState 會回傳 mCurrentState,代表此 layer 目前狀態。得到狀態後,首先檢查是否發生尺寸上的變化(
sizeChanged),如果有發生改變就執行 mSurfaceFlingerConsumer->setDefaultBufferSize(temp.requested.w, temp.requested.h); 這裡實際運作情況待補,現在就把他理解成會根據不同的尺寸來設定 mDefaultWidth 跟 mDefaultHeight,之後會根據這兩個值來設定 Buffer 大小。
接著
if (!isFixedSize()) {
const bool resizePending = (temp.requested.w != temp.active.w) ||
(temp.requested.h != temp.active.h);
if (resizePending) {
// don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// the drawing state will be updated only once we receive a buffer
// with the correct size.
//
// in particular, we want to make sure the clip (which is part
// of the geometry state) is latched together with the size but is
// latched immediately when no resizing is involved.
flags |= eDontUpdateGeometryState;
}
}
// always set active to requested, unless we're asked not to
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
Layer::State& editTemp(currentState());
editTemp.active = temp.requested;
}
調用 isFixedSize 來判斷 mCurrentScalingMode 是否為 FixedSize mode,如果不是 fixed size 的則進去判斷 current state 中的 request 跟 active 的 width 跟 height 是否相同,不相同的話,就把 eDontUpdateGeometryState 這個 flag 拉起來。然後進入下列的幾個判斷式
// always set active to requested, unless we're asked not to
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
Layer::State& editTemp(currentState());
editTemp.active = temp.requested;
}
if (front.active != temp.active) {
// invalidate and recompute the visible regions if needed
flags |= Layer::eVisibleRegion;
}
if (temp.sequence != front.sequence) {
// invalidate and recompute the visible regions if needed
flags |= eVisibleRegion;
this->contentDirty = true;
// we may use linear filtering, if the matrix scales us
const uint8_t type = temp.transform.getType();
mNeedsFiltering = (!temp.transform.preserveRects() ||
(type >= Transform::SCALE));
}
上面有三個 if 判斷式,第一個就是如果 eDontUpdateGeometryState 被拉起來,那就不會把 requested assign 給 active,如果這邊猜測沒有問題的話,接下來的判斷式
if (front.active != temp.active)
會檢查上一次跟這一次的 active 一不一樣,不一樣的話會拉 eVisibleRegion 表示 visible region 有改變。
第三個判斷式是判斷 drawing 跟 current 的 sequence 值是否一樣,mCurrentState.sequence 在很多 Layer 的改變的操作被呼叫時(例如:setLayer、setSize 等)就會被累加一 。如果不一樣的話也拉 eVisibleRegion,然後將 contentDirty 設為 true ,接著會修改 mNeedsFiltering 值。
雖然從程式邏輯上很容易可以理解這些步驟,但是這些東西到底是要做什麼的從這邊不太容易看出來。尤其是
eDontUpdateGeometryState 這個東西該怎麼理解 。
之後理解了再補上。
最後會呼叫 commitTransaction(),這個 function 內容如下,很簡單。
void Layer::commitTransaction() {
mDrawingState = mCurrentState;
}
最後 return flag,然後我們離開 doTrasaction 啦! 程式回到 handleTransactionLocked,doTrasaction 之後馬上有人檢查 return 的值
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
如果有任何一個 Layer 有變動,就會把 mVisibleRegionsDirty 設為 true。
========================================================================
接著再繼續 handleTransactionLocked,第二個要確認的 flag 是 eDisplayTransactionNeeded
從上面可以稍微了解到 eDisplayTransactionNeeded 是在 createDisplay 或 onHotplugReceived 發生時會被拉起來。所以這邊我可以稍微猜想一下他會做什麼。基本上他應該會‧‧‧‧,痾‧‧‧,算了!看 code 吧。
以 createDisplay 為例,createDisplay 中會呼叫
mCurrentState.displays.add(token, info);
加入一個 DisplayDeviceState 進 display 這個 DefaultKeyedVector 中。 DefaultKeyedVector 宣告如下
class DefaultKeyedVector : public KeyedVector<KEY, VALUE>
它繼承自 KeyedVector,可以透過 valueFor(const KEY& key)用 key 值找到對應的物件(value),或透過 isIdenticalTo(const KeyedVector& rhs) 比對兩個 KeyedVector 是否相同。
所以當 createDisplay 發生時,下面兩個 if 判斷式應該都會成立,所以這個 case 主要的工作就是 if (!curr.isIdenticalTo(draw)) 成立後裡面做的事。(這邊舉 createDisplay 只是要知道有那些時候會進入這個條件,後面的介紹跟這個 function 在沒關係。)
if (transactionFlags & eDisplayTransactionNeeded) {
// here we take advantage of Vector's copy-on-write semantics to
// improve performance by skipping the transaction entirely when
// know that the lists are identical
const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
if (!curr.isIdenticalTo(draw)) {
●
●
●
}
}
而裡面的工作主要是歷遍整個 mDrawingState.displays 中的所有物件,然後利用
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
來判斷是否存在於 mCurrentState.displays 中, j < 0 的話表示沒有,代表在新的 state 中已被移除。如果已被移除,判斷如果不是
DISPLAY_PRIMARY ( 代表手機螢幕) 則先將 defaultDisplay makeCurrent (此處跟 EGL 相關,簡單講就是將 display 設回手機螢幕),接著在移除這個 display 。
如果 j > 0 表示他還沒被移除,就檢查一下他的狀態是否有被改變,有的話再做對應的動作 (setLayerStack、setProjection 等等)。
上面是遍歷整個 mDrawingState.displays 來判斷是否有物件被移除,接著反過來歷遍整個 mCurrentState.displays 看是否有物件被新加進來,然後作對應的處理 (先略)。
========================================================================
在 4.2 的 MessageQueue::INVALIDATE 的訊息處理還有兩個 function 被執行
handleMessageInvalidate();
signalRefresh();
signalRefresh 看似會發 MessageQueue::REFRESH ,所以等於還是會執行 handleMessageRefresh
裡面還有好幾個 function 。