2014年2月9日 星期日

Android 4.3 surfaceflinger 中的 handleMessageTransaction

在我工作的平台上,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 。



沒有留言:

張貼留言