Android P 圖形顯示系統(七) SurfaceFlinger合成流程(二)

SurfaceFlinger合成流程(二)

SurfaceFlinger合成流程

MessageQueue中分發兩個消息,一個INVALIDATE,一個REFRESH,SurfaceFlinger對這兩個消息的響應過程,就是合成的過程。

消息INVALIDATE處理

在onFrameAvailable時,調用signalLayerUpdate,將觸發INVALIDATE消息。SurfaceFlinger收到這個消息的處理如下:

void SurfaceFlinger::onMessageReceived(int32_t what) {
    ATRACE_CALL();
    switch (what) {
        case MessageQueue::INVALIDATE: {
            bool frameMissed = !mHadClientComposition &&
                    mPreviousPresentFence != Fence::NO_FENCE &&
                    (mPreviousPresentFence->getSignalTime() ==
                            Fence::SIGNAL_TIME_PENDING);
            ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
            if (mPropagateBackpressure && frameMissed) {
                signalLayerUpdate();
                break;
            }

            updateVrFlinger();

            bool refreshNeeded = handleMessageTransaction();
            refreshNeeded |= handleMessageInvalidate();
            refreshNeeded |= mRepaintEverything;
            if (refreshNeeded) {
                signalRefresh();
            }
            break;
        }
        case MessageQueue::REFRESH: {
            handleMessageRefresh();
            break;
        }
    }
}

在INVALIDATE過程中,主要做以下處理:

  • 對丟幀的處理

如果丟幀,且mPropagateBackpressure為true,mPropagateBackpressure表示顯示給壓力了。顯示說,太慢了,都丟幀了,給點壓力,上層趕緊處理。mPropagateBackpressure是在SurfaceFlinger的構造函數中初始化的,受debug.sf.disable_backpressure屬性的控制。

    property_get("debug.sf.disable_backpressure", value, "0");
    mPropagateBackpressure = !atoi(value);
  • 更新VR updateVrFlinger

這個只有在VR模式下才會起作用,我們這里先不管VR的事。

  • 處理Transition

Transition的處理,前面我們已經說過,只是當時不清楚是什么時候觸發的,現在清楚了。Vsync到來后,觸發INVALIDATE消息時先去處理Transition。處理的過程就是前面已經說過的handleMessageTransaction,有需要可以回頭去看看。這個過程就是處理應用傳過來的各種Transition,需要記住的是在commit Transition時,又個狀態的更替,mCurrentState賦值給了mDrawingState

void SurfaceFlinger::commitTransaction()
{
    ... ...

    mDrawingState = mCurrentState;
    mDrawingState.traverseInZOrder([](Layer* layer) {
        layer->commitChildList();
    });
    ... ...
}

所以SurfaceFlinger兩個狀態:
mCurrentState狀態, 準備數據,應用傳過來的數據保存在mCurrentState中。
mDrawingState狀態,進程合成狀態,需要進行合成的數據保存在mDrawingState中。

也就是說,每次合成時,先更新一下狀態數據。每一層Layer也需要去更新狀態數據。

  • 處理Invalidate
    這是一個重要的流程,handleMessageInvalidate函數如下:
bool SurfaceFlinger::handleMessageInvalidate() {
    ATRACE_CALL();
    return handlePageFlip();
}

主要是調用handlePageFlip,做Page的Flip。

bool SurfaceFlinger::handlePageFlip()
{
    ALOGV("handlePageFlip");

    nsecs_t latchTime = systemTime();

    bool visibleRegions = false;
    bool frameQueued = false;
    bool newDataLatched = false;

    mDrawingState.traverseInZOrder([&](Layer* layer) {
        if (layer->hasQueuedFrame()) {
            frameQueued = true;
            if (layer->shouldPresentNow(mPrimaryDispSync)) {
                mLayersWithQueuedFrames.push_back(layer);
            } else {
                layer->useEmptyDamage();
            }
        } else {
            layer->useEmptyDamage();
        }
    });

    for (auto& layer : mLayersWithQueuedFrames) {
        const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
        layer->useSurfaceDamage();
        invalidateLayerStack(layer, dirty);
        if (layer->isBufferLatched()) {
            newDataLatched = true;
        }
    }

    mVisibleRegionsDirty |= visibleRegions;

    // If we will need to wake up at some time in the future to deal with a
    // queued frame that shouldn't be displayed during this vsync period, wake
    // up during the next vsync period to check again.
    if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
        signalLayerUpdate();
    }

    // Only continue with the refresh if there is actually new work to do
    return !mLayersWithQueuedFrames.empty() && newDataLatched;
}

mLayersWithQueuedFrames,用于標記那些已經有Frame的Layer,這得從Layer的onFrameAvailable說起。

void BufferLayer::onFrameAvailable(const BufferItem& item) {
    // Add this buffer from our internal queue tracker
    { // Autolock scope
        Mutex::Autolock lock(mQueueItemLock);
        mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
                                                item.mGraphicBuffer->getHeight(),
                                                item.mFrameNumber);
        // Reset the frame number tracker when we receive the first buffer after
        // a frame number reset
        if (item.mFrameNumber == 1) {
            mLastFrameNumberReceived = 0;
        }

        // Ensure that callbacks are handled in order
        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
                                                               ms2ns(500));
            if (result != NO_ERROR) {
                ALOGE("[%s] Timed out waiting on callback", mName.string());
            }
        }

        mQueueItems.push_back(item);
        android_atomic_inc(&mQueuedFrames);

        // Wake up any pending callbacks
        mLastFrameNumberReceived = item.mFrameNumber;
        mQueueItemCondition.broadcast();
    }

    mFlinger->signalLayerUpdate();
}

onFrameAvailable時,先將Buffer的窗口屬性保存在mInterceptor中,這里我們暫時不看,記得標記一下。然后對FrameNumber進行處理,一是確保FrameNumber被重置時,重置mLastFrameNumberReceived,二時,確保FrameNumber的順序。之后,將新過來的BufferItem,push到mQueueItems中,對mQueuedFrames數進行+1。最后才觸發SurfaceFlinger進行signalLayerUpdate。

回到handlePageFlip。所以,對于觸發SurfaceFlinger進行signalLayerUpdate的Layer,hasQueuedFrame為true,是有Queued的Frame的。

但是mLayersWithQueuedFrames還要一個條件,shouldPresentNow。

bool BufferLayer::shouldPresentNow(const DispSync& dispSync) const {
    if (mSidebandStreamChanged || mAutoRefresh) {
        return true;
    }

    Mutex::Autolock lock(mQueueItemLock);
    if (mQueueItems.empty()) {
        return false;
    }
    auto timestamp = mQueueItems[0].mTimestamp;
    nsecs_t expectedPresent = mConsumer->computeExpectedPresent(dispSync);

    // Ignore timestamps more than a second in the future
    bool isPlausible = timestamp < (expectedPresent + s2ns(1));
    ALOGW_IF(!isPlausible,
             "[%s] Timestamp %" PRId64 " seems implausible "
             "relative to expectedPresent %" PRId64,
             mName.string(), timestamp, expectedPresent);

    bool isDue = timestamp < expectedPresent;
    return isDue || !isPlausible;
}

在shouldPresentNow的判斷邏輯中,首先根據DispSync,去計算期望顯示的時間。再看看Buffer的時間戳和期望顯示的時間,如果Buffer的時間還沒有到,且和期望顯示的時間之間差不到1秒,那么shouldPresentNow成立。該Layer標記為mLayersWithQueuedFrames;否則,Layer使用空的DamageRegion。記住這個DamageRegion

void BufferLayer::useEmptyDamage() {
    surfaceDamageRegion.clear();
}

繼續handlePageFlip函數分析。

  • 對mLayersWithQueuedFrames標記的Layer進行處理

首先,通過latchBuffer獲取Layer的Buffer;再更新Surface的Damage;再通過invalidateLayerStack去刷新臟區域,驗證LayerStack。記住LayerStack這個概念。處理這塊稍后繼續~~~

注意這里重新signalLayerUpdate的邏輯。

    if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
        signalLayerUpdate();
    }

有BufferQueue過來,但是還沒有到顯示時間(mLayersWithQueuedFrames為空),或者沒有獲取到Buffer。重新觸發一次更新~

注意handlePageFlip的返回值,有Layer要顯示,且獲取到Buffer時,才返回true。注意這里的mVisibleRegionsDirty,mVisibleRegionsDirty,臟區域,表示可見區域有更新。

handlePageFlip獲取Buffer

繼續前面的Buffer的處理

    for (auto& layer : mLayersWithQueuedFrames) {
        const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
        layer->useSurfaceDamage();
        invalidateLayerStack(layer, dirty);
        if (layer->isBufferLatched()) {
            newDataLatched = true;
        }
    }
  • 獲取 Buffer
    Layer的latchBuffer函數比較長,這里將去獲取Producer Queue過來的數據。我們分段來看:
* frameworks/native/services/surfaceflinger/BufferLayer.cpp

Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
    ATRACE_CALL();

    if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
        // mSidebandStreamChanged was true
        mSidebandStream = mConsumer->getSidebandStream();
        // replicated in LayerBE until FE/BE is ready to be synchronized
        getBE().compositionInfo.hwc.sidebandStream = mSidebandStream;
        if (getBE().compositionInfo.hwc.sidebandStream != NULL) {
            setTransactionFlags(eTransactionNeeded);
            mFlinger->setTransactionFlags(eTraversalNeeded);
        }
        recomputeVisibleRegions = true;

        const State& s(getDrawingState());
        return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
    }
    ... ...

android_atomic_acquire_cas是比較-設置的原子操縱函數,如果變量第三個參數和第一個相等,那么將第二個參數賦值給第三個參數,成功返回0。mSidebandStreamChanged為true,說明Sideband流改變了,這里處理后,就返回了。

* frameworks/native/services/surfaceflinger/BufferLayer.cpp
    ... ...

    Region outDirtyRegion;
    ... ... // 如果條件不滿足,直接返回

    const State& s(getDrawingState());
    const bool oldOpacity = isOpaque(s);
    sp<GraphicBuffer> oldBuffer = getBE().compositionInfo.mBuffer;

    if (!allTransactionsSignaled()) {
        mFlinger->signalLayerUpdate();
        return outDirtyRegion;
    }

oldBuffer,前一幀的Buffer~
allTransactionsSignaled,確保所有的Fence都已經Signal出來。記住這個點,Fence相關的知識。

* frameworks/native/services/surfaceflinger/BufferLayer.cpp
    ... ...

    bool queuedBuffer = false;
    LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
                    getProducerStickyTransform() != 0, mName.string(),
                    mOverrideScalingMode, mFreezeGeometryUpdates);
    status_t updateResult =
            mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
                                                    &mAutoRefresh, &queuedBuffer,
                                                    mLastFrameNumberReceived);
    if (updateResult == BufferQueue::PRESENT_LATER) {
        mFlinger->signalLayerUpdate();
        return outDirtyRegion;
    } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
        if (queuedBuffer) {
            Mutex::Autolock lock(mQueueItemLock);
            mQueueItems.removeAt(0);
            android_atomic_dec(&mQueuedFrames);
        }
        return outDirtyRegion;
    } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
        if (queuedBuffer) {
            Mutex::Autolock lock(mQueueItemLock);
            mQueueItems.clear();
            android_atomic_and(0, &mQueuedFrames);
        }

        mUpdateTexImageFailed = true;

        return outDirtyRegion;
    }

LayerRejecter顧名思義,用以決定是否拒絕這個Layer。updateTexImage 很關鍵,這里去獲取的Buffer,將通過acquireBuffer函數去請求Buffer。前面我們已經說過BufferQueue的acquireBuffer流程。

updateTexImage有多種返回結果:
PRESENT_LATER:稍后顯示,暫時不顯示,觸發SurfaceFlinger重新刷新signalLayerUpdate。
BUFFER_REJECTED: Buffer被Reject掉,這一幀數據將不再被顯示,從mQueueItems中去掉這一幀的Buffer,mQueuedFrames也-1。
更新失敗或出錯:處理和BUFFER_REJECTED類似。

updateTexImage的流程稍后再看,我們將這個函數讀完。

  • frameworks/native/services/surfaceflinger/BufferLayer.cpp
    ... ...

    if (queuedBuffer) {
    // Autolock scope
    auto currentFrameNumber = mConsumer->getFrameNumber();

      Mutex::Autolock lock(mQueueItemLock);
    
      // 刪掉updateTexImage中已經被丟棄的Buffer
      while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
          mQueueItems.removeAt(0);
          android_atomic_dec(&mQueuedFrames);
      }
    
      mQueueItems.removeAt(0);
    

    }

    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) ||
    mAutoRefresh) {
    mFlinger->signalLayerUpdate();
    }

如果獲取Buffer后,隊列中還有其他的Buffer,觸發SurfaceFlinger去再做一次刷新signalLayerUpdate,在下一個Vsync再處理。

* frameworks/native/services/surfaceflinger/BufferLayer.cpp
    ... ...
    
    // update the active buffer
    getBE().compositionInfo.mBuffer =
            mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
    // replicated in LayerBE until FE/BE is ready to be synchronized
    mActiveBuffer = getBE().compositionInfo.mBuffer;
    if (getBE().compositionInfo.mBuffer == NULL) {
        // this can only happen if the very first buffer was rejected.
        return outDirtyRegion;
    }

更新Active的Buffer,mActiveBuffer就是我們這次合成,該Layer的數據。如果沒有獲取到,返回。

  • frameworks/native/services/surfaceflinger/BufferLayer.cpp
    ... ...

    mBufferLatched = true;
    mPreviousFrameNumber = mCurrentFrameNumber;
    mCurrentFrameNumber = mConsumer->getFrameNumber();

    {
    Mutex::Autolock lock(mFrameEventHistoryMutex);
    mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
    }

mFrameEventHistory,記錄Frame的歷史,Producer和Consumer對Frame的處理。

* frameworks/native/services/surfaceflinger/BufferLayer.cpp
    ... ...

    mRefreshPending = true;
    mFrameLatencyNeeded = true;
    if (oldBuffer == NULL) {
        // the first time we receive a buffer, we need to trigger a
        // geometry invalidation.
        recomputeVisibleRegions = true;
    }

    setDataSpace(mConsumer->getCurrentDataSpace());

    Rect crop(mConsumer->getCurrentCrop());
    const uint32_t transform(mConsumer->getCurrentTransform());
    const uint32_t scalingMode(mConsumer->getCurrentScalingMode());
    if ((crop != mCurrentCrop) ||
        (transform != mCurrentTransform) ||
        (scalingMode != mCurrentScalingMode)) {
        mCurrentCrop = crop;
        mCurrentTransform = transform;
        mCurrentScalingMode = scalingMode;
        recomputeVisibleRegions = true;
    }

    if (oldBuffer != NULL) {
        uint32_t bufWidth = getBE().compositionInfo.mBuffer->getWidth();
        uint32_t bufHeight = getBE().compositionInfo.mBuffer->getHeight();
        if (bufWidth != uint32_t(oldBuffer->width) ||
            bufHeight != uint32_t(oldBuffer->height)) {
            recomputeVisibleRegions = true;
        }
    }

    mCurrentOpacity = getOpacityForFormat(getBE().compositionInfo.mBuffer->format);
    if (oldOpacity != isOpaque(s)) {
        recomputeVisibleRegions = true;
    }

這里主要是根據新的Buffer的屬性,和上一幀Buffer的的數據,做比較,看看是否需要重新去計算可見區域。

* frameworks/native/services/surfaceflinger/BufferLayer.cpp
    ... ...

    {
        Mutex::Autolock lock(mLocalSyncPointMutex);
        auto point = mLocalSyncPoints.begin();
        while (point != mLocalSyncPoints.end()) {
            if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) {
                // This sync point must have been added since we started
                // latching. Don't drop it yet.
                ++point;
                continue;
            }

            if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
                point = mLocalSyncPoints.erase(point);
            } else {
                ++point;
            }
        }
    }

    // FIXME: postedRegion should be dirty & bounds
    Region dirtyRegion(Rect(s.active.w, s.active.h));

    // transform the dirty region to window-manager space
    outDirtyRegion = (getTransform().transform(dirtyRegion));

    return outDirtyRegion;
}

最后,是對SyncPoint進行處理,新latch的buffer相關的Syncpoint都刪掉。返回的是outDirtyRegion,對dirtyRegion做了transform變換后的區域大小。

我們再回過頭看updateTexImage,updateTexImage函數實現如下:

status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
                                             bool* autoRefresh, bool* queuedBuffer,
                                             uint64_t maxFrameNumber) {
    ... ...

    BufferItem item;

    status_t err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber);
    if (err != NO_ERROR) {
        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
            err = NO_ERROR;
        } else if (err == BufferQueue::PRESENT_LATER) {
            // return the error, without logging
        } else {
            BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
        }
        return err;
    }

    if (autoRefresh) {
        *autoRefresh = item.mAutoRefresh;
    }

    if (queuedBuffer) {
        *queuedBuffer = item.mQueuedBuffer;
    }

    int slot = item.mSlot;
    if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
        return BUFFER_REJECTED;
    }

    // Release the previous buffer.
    err = updateAndReleaseLocked(item, &mPendingRelease);
    if (err != NO_ERROR) {
        return err;
    }

    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
        err = bindTextureImageLocked();
    }

    return err;
}

updateTexImage過程大致如下:
1.拿到一塊Buffer,從BufferQueue中,acquireBufferLocked

status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
                                                  uint64_t maxFrameNumber) {
    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber);
    if (err != NO_ERROR) {
        return err;
    }

    // If item->mGraphicBuffer is not null, this buffer has not been acquired
    // before, so any prior EglImage created is using a stale buffer. This
    // replaces any old EglImage with a new one (using the new buffer).
    if (item->mGraphicBuffer != NULL) {
        mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
    }

    return NO_ERROR;
}

acquireBufferLocked通過父類,ConsumerBase的acquireBufferLocked函數去獲取Buffer,如果Buffer不為空,創建Eglimage。

在ConsumerBase的acquireBufferLocked中,正式通過BufferQueue的BufferQueueConsumer去acquireBuffer。代碼如下:

status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
        nsecs_t presentWhen, uint64_t maxFrameNumber) {
    if (mAbandoned) {
        CB_LOGE("acquireBufferLocked: ConsumerBase is abandoned!");
        return NO_INIT;
    }

    status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
    if (err != NO_ERROR) {
        return err;
    }

    if (item->mGraphicBuffer != NULL) {
        if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
            freeBufferLocked(item->mSlot);
        }
        mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
    }

    mSlots[item->mSlot].mFrameNumber = item->mFrameNumber;
    mSlots[item->mSlot].mFence = item->mFence;

    CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64,
            item->mSlot, item->mFrameNumber);

    return OK;
}

acquireBuffer的流程前面已經說過,拿到Buffer后,將Buffer保存在mSlots[item->mSlot].mGraphicBuffer中。同時更新mFrameNumber和mFence。

2.檢測Buffer可用不,不可用就Reject掉,rejecter->reject
相關的邏輯在類LayerRejecter中:

* frameworks/native/services/surfaceflinger/LayerRejecter.cpp

代碼這里就不貼了,在reject邏輯中,其一是判斷釋放需要重新計算可見區域mRecomputeVisibleRegions;其二,看看Buffer的屬性和狀態描述中的屬性釋放吻合,不一直就reject掉;

3.更新Buffer,釋放上一個Buffer,updateAndReleaseLocked

updateAndReleaseLocked函數實現如下:

status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
                                                     PendingRelease* pendingRelease) {
    status_t err = NO_ERROR;

    int slot = item.mSlot;

    // Do whatever sync ops we need to do before releasing the old slot.
    if (slot != mCurrentTexture) {
        err = syncForReleaseLocked();
        if (err != NO_ERROR) {
            // Release the buffer we just acquired.  It's not safe to
            // release the old buffer, so instead we just drop the new frame.
            // As we are still under lock since acquireBuffer, it is safe to
            // release by slot.
            releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
            return err;
        }
    }

    BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
             mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, slot,
             mSlots[slot].mGraphicBuffer->handle);

    // Hang onto the pointer so that it isn't freed in the call to
    // releaseBufferLocked() if we're in shared buffer mode and both buffers are
    // the same.
    sp<Image> nextTextureImage = mImages[slot];

    // release old buffer
    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
        if (pendingRelease == nullptr) {
            status_t status =
                    releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer());
            if (status < NO_ERROR) {
                BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
                         status);
                err = status;
                // keep going, with error raised [?]
            }
        } else {
            pendingRelease->currentTexture = mCurrentTexture;
            pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
            pendingRelease->isPending = true;
        }
    }

    // Update the BufferLayerConsumer state.
    mCurrentTexture = slot;
    mCurrentTextureImage = nextTextureImage;
    mCurrentCrop = item.mCrop;
    mCurrentTransform = item.mTransform;
    mCurrentScalingMode = item.mScalingMode;
    mCurrentTimestamp = item.mTimestamp;
    mCurrentDataSpace = item.mDataSpace;
    mCurrentHdrMetadata = item.mHdrMetadata;
    mCurrentFence = item.mFence;
    mCurrentFenceTime = item.mFenceTime;
    mCurrentFrameNumber = item.mFrameNumber;
    mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse;
    mCurrentSurfaceDamage = item.mSurfaceDamage;

    computeCurrentTransformMatrixLocked();

    return err;
}

該函數中,處理Fence相關的邏輯比較多,后續我們將用專門的章節來講述Android中Fence同步機制,這里先不要太關注它。該函數中主要作用如下:

  • syncForReleaseLocked,mCurrentTexture是上一個Buffer的序號slot,我們需要給舊Buffer設置ReleaseFence。
  • releaseBufferLocked,release掉舊的Buffer,先加到mPendingRelease中,待合成完成后release掉Pending的Buffer。
  • 更新BufferLayerConsumer的狀態,Buffer的屬性都保存到mCurrent**定義的屬性中。

到此updateTexImage函數完成。

latchBuffer中,再通過getCurrentBuffer去獲取Consumer中已經更了Buffer。代碼如下:

sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
    Mutex::Autolock lock(mMutex);

    if (outSlot != nullptr) {
        *outSlot = mCurrentTexture;
    }

    return (mCurrentTextureImage == nullptr) ? NULL : mCurrentTextureImage->graphicBuffer();
}

mCurrentTextureImage,也是按照slot從mImages中獲取的,前面acquireBuffer時,Buffer根據slot保存在mImages中。

到此,Layer中已經獲取到Buffer的數據。需要注意的是,這不是對單個的Layer,而是所有的mLayersWithQueuedFrames都會走上面的流程,而每個Layer有自己的BufferLayerConsumer和BufferQueue。

我們先來看看看這里遇到的幾個類間的相互關系:


Layer和Buffer間關系

還算比較清晰吧~這里我們只關心Buffer從哪兒來,到哪兒去就行了

拿到Buffer后,更新Layer的Damage,useSurfaceDamage,Damage表示Layer的那些區域被破壞了,被破壞的區域需要重新合成顯示。

const Region& BufferLayerConsumer::getSurfaceDamage() const {
    return mCurrentSurfaceDamage;
}

surfaceDamage就前面updateTexture時一起更新的mCurrentSurfaceDamage。

invalidateLayerStack的處理如下:

void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        const sp<DisplayDevice>& hw(mDisplays[dpy]);
        if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
            hw->dirtyRegion.orSelf(dirty);
        }
    }
}

layerStack,Layer的棧,Android支持多個屏幕,layer可以定制化的只顯示到某個顯示屏幕上。其中就是靠layerStack來實現的。Layer的stack值如果和DisplayDevice的stack值一樣,那說明這個layer是屬于這個顯示屏幕的。

INVALIDATE消息處理,基本完成。如果需要刷新,觸發刷新的消息:

            if (refreshNeeded) {
                signalRefresh();
            }

什么時候需要刷新?

  • 有新的Transaction處理
  • PageFlip時,有Buffer更新!~
  • 有重新合成請求時mRepaintEverything,這是響應HWC的請求時觸發的。

刷新消息REFRESH處理

signalRefresh函數如下:

void SurfaceFlinger::signalRefresh() {
    mRefreshPending = true;
    mEventQueue.refresh();
}

還是通過MessageQueue來進行分發~

void MessageQueue::refresh() {
    mHandler->dispatchRefresh();
}

最終,還是會調回SurfaceFlinger的onMessageReceived函數,這是這里的massage為REFRESH。注意,這過程中不用去等Vsync的,INVALIDATE時,是需要等Vsync的。也就是說,INVALIDATE和REFRESH是在同一個Vsync周期內完成的。

SurfaceFlinger收到REFRESH請求后,在 handleMessageRefresh 函數中進行處理。

void SurfaceFlinger::handleMessageRefresh() {
    ATRACE_CALL();

    mRefreshPending = false;

    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);

    preComposition(refreshStartTime);
    rebuildLayerStacks();
    setUpHWComposer();
    doDebugFlashRegions();
    doTracing("handleRefresh");
    doComposition();
    postComposition(refreshStartTime);

    mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);

    mHadClientComposition = false;
    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
        const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
        mHadClientComposition = mHadClientComposition ||
                getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
    }

    mLayersWithQueuedFrames.clear();
}

handleMessageRefresh 函數中,包含了刷新一幀顯示數據所有的流程。下面我們分別來進行說明。

合成前處理 preComposition

preComposition函數如下:

void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
{
    ATRACE_CALL();
    ALOGV("preComposition");

    bool needExtraInvalidate = false;
    mDrawingState.traverseInZOrder([&](Layer* layer) {
        if (layer->onPreComposition(refreshStartTime)) {
            needExtraInvalidate = true;
        }
    });

    if (needExtraInvalidate) {
        signalLayerUpdate();
    }
}

在合成前,先遍歷所有需要進行合成的Layer,調Layer的onPreComposition方法。

ColorLayer的onPreComposition,返回值是固定的,為true;BufferLayer的onPreComposition如下:

bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
    if (mBufferLatched) {
        Mutex::Autolock lock(mFrameEventHistoryMutex);
        mFrameEventHistory.addPreComposition(mCurrentFrameNumber,
                                             refreshStartTime);
    }
    mRefreshPending = false;
    return mQueuedFrames > 0 || mSidebandStreamChanged ||
            mAutoRefresh;
}

onPreComposition中主要作用為:

  • mFrameEventHistory記錄PreComposition事件
  • 判斷是否需要再觸發SurfaceFlinger繼續接受Vsync進行合成
    這3中情況需要:如果mQueuedFrames的值大于0,說明這個時候BufferQueue中還有Buffer,之前我們在acquireBuffer的時候,已經做了-1操縱;SidebandStream改變;或者是自動刷新模式。

如果需要再觸發SurfaceFlinger工作,調signalLayerUpdate函數。

重構Layer的Stack rebuildLayerStacks

現在,我們需要合成顯示的Layer數據,都保存在mDrawingState的layersSortedByZ中,且是按照z-order的順序進行存放。那么rebuild Layer又是做什么呢?

void SurfaceFlinger::rebuildLayerStacks() {
    ATRACE_CALL();
    ALOGV("rebuildLayerStacks");

    // rebuild the visible layer list per screen
    if (CC_UNLIKELY(mVisibleRegionsDirty)) {
        ATRACE_NAME("rebuildLayerStacks VR Dirty");
        mVisibleRegionsDirty = false;
        invalidateHwcGeometry();

        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            Region opaqueRegion;
            Region dirtyRegion;
            Vector<sp<Layer>> layersSortedByZ;
            Vector<sp<Layer>> layersNeedingFences;
            const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
            const Transform& tr(displayDevice->getTransform());
            const Rect bounds(displayDevice->getBounds());
            if (displayDevice->isDisplayOn()) {
                computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);

                ... ...
            }
            displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
            displayDevice->setLayersNeedingFences(layersNeedingFences);
            displayDevice->undefinedRegion.set(bounds);
            displayDevice->undefinedRegion.subtractSelf(
                    tr.transform(opaqueRegion));
            displayDevice->dirtyRegion.orSelf(dirtyRegion);
        }
    }
}

rebuild Layer的前提是存在臟區域,mVisibleRegionsDirty為true。invalidateHwcGeometry重置mGeometryInvalid標記,這個標識后面會用到。

Android支持多個屏幕,每個屏幕的顯示數據并不是完全一樣的,每個Display是分開合成的;也就是說,layersSortedByZ中的layer需要根據顯示屏的特性,分別進行合成,合成后的數據,送給各自的顯示屏。

mDisplays是當前系統中的顯示屏,isDisplayOn判斷屏幕是否是打開的。主屏幕是默認支持的,處于打開狀態。

computeVisibleRegions,計算可見區域。Layer中有很多個區域,不太好理解。computeVisibleRegions函數實現如下:

void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
        Region& outDirtyRegion, Region& outOpaqueRegion)
{
    ATRACE_CALL();
    ALOGV("computeVisibleRegions");

    Region aboveOpaqueLayers;
    Region aboveCoveredLayers;
    Region dirty;

    outDirtyRegion.clear();

    mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
        // start with the whole surface at its current location
        const Layer::State& s(layer->getDrawingState());

        // only consider the layers on the given layer stack
        if (!layer->belongsToDisplay(displayDevice->getLayerStack(), displayDevice->isPrimary()))
            return;

        Region opaqueRegion;

        Region visibleRegion;

        Region coveredRegion;

        Region transparentRegion;

我們先來看Display的幾個關于區域的概念:

  • 臟區域 dirtyRegion
    計算臟區域時,outDirtyRegion先清空~ 然后遍歷mDrawingState中的Layer,如果Layer不屬于Display,那么就返回了,outDirtyRegion為空。

  • 非透明區域 opaqueRegion
    Surface(Layer)完全不透明的區域

  • 可見區域 visibleRegion
    Layer可以被看見的區域,包括不完全透明的區域。原則上,這就是整個Surface減去非透明區域。

  • 被覆蓋區域 coveredRegion
    Surface被上面的Surface覆蓋的區域,包括被透明區域覆蓋的區域。

  • 透明區域 transparentRegion
    Surface完全透明的部分,如果沒有可見的非透明區域,這個Layer就可以從Layer列表中刪掉。它并不影響該Layer本身或其下方Layer的可見區域大小。這個區域可能不太準,如果App不遵守SurfaceView的限制,可悲的是,確實有不遵守的。

回到computeVisibleRegions函數,其是按照z-order進行反序號遍歷的,所以從最上面開始遍歷。

void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
        Region& outDirtyRegion, Region& outOpaqueRegion)
{
        ... ...
        // handle hidden surfaces by setting the visible region to empty
        if (CC_LIKELY(layer->isVisible())) {
            const bool translucent = !layer->isOpaque(s);
            Rect bounds(layer->computeScreenBounds());
            visibleRegion.set(bounds);
            Transform tr = layer->getTransform();
            if (!visibleRegion.isEmpty()) {
                // 將完全透明區域從可見區域中刪掉
                if (translucent) {
                    if (tr.preserveRects()) {
                        // transform 透明區域
                        transparentRegion = tr.transform(s.activeTransparentRegion);
                    } else {
                        // 太復雜了,做不了優化
                        transparentRegion.clear();
                    }
                }

                // compute the opaque region
                const int32_t layerOrientation = tr.getOrientation();
                if (layer->getAlpha() == 1.0f && !translucent &&
                        ((layerOrientation & Transform::ROT_INVALID) == false)) {
                    // the opaque region is the layer's footprint
                    opaqueRegion = visibleRegion;
                }
            }
        }

這里用到Layer的幾個函數:

  • isOpaque 說明Layer是非透明的Layer,這個是上層應用設置的,注意,我們這里說的應用不只說App,也包括Android的Framework,是泛指。

  • computeScreenBounds 計算Layer的在屏幕上的大小
    computeScreenBounds函數如下:

Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
    const Layer::State& s(getDrawingState());
    Rect win(s.active.w, s.active.h);

    if (!s.crop.isEmpty()) {
        win.intersect(s.crop, &win);
    }

    Transform t = getTransform();
    win = t.transform(win);

    if (!s.finalCrop.isEmpty()) {
        win.intersect(s.finalCrop, &win);
    }

    const sp<Layer>& p = mDrawingParent.promote();
    if (p != nullptr) {
        Rect bounds = p->computeScreenBounds(false);
        bounds.intersect(win, &win);
    }

    if (reduceTransparentRegion) {
        auto const screenTransparentRegion = t.transform(s.activeTransparentRegion);
        win = reduce(win, screenTransparentRegion);
    }

    return win;
}

s.active.ws.active.h,是Layer本身的大小,用win表示。
crop是Layer的源剪截區域,由上層設置,表示該Layer只截取crop的區域進行合成顯示,這個區域可以能比win大,也可能比win小,所以要和win做一個交集運算,截取兩個區域重復的部分。
finalCrop和crop類似,只是這里的finalCrop是處理win做了變換后的,最終的區域。finalCrop也是上層設置的。

Layer本身的crop處理完后,還要和父Layer的區域做一個交集運算,子Layer不讓超過父Layer的大小?
默認的需要減掉透明區域的,reduceTransparentRegion默認參數為true。

computeScreenBounds的返回值,就是Layer可見區域的大小,visibleRegion區域后續還會被裁剪。

  • getTransform 獲取 Layer的變換矩陣
    屏幕有旋轉,需要做變換,去適配顯示屏幕

回到 computeVisibleRegions函數,計算完可見區域,計算非透明區域,一般情況下,如果layer是非透明的,非透明區域就是可見區域。

void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
        Region& outDirtyRegion, Region& outOpaqueRegion)
{
        ... ...
        // 遍歷時,第一層時,aboveCoveredLayers為空,coveredRegion也是為空,最上面一層是沒有被覆蓋的,當然為空。
        coveredRegion = aboveCoveredLayers.intersect(visibleRegion);

        // 更新aboveCoveredLayers,該層之下的Layer都被該層Layer覆蓋,所以這里和可見區域做一個或操縱,最下面的區域被覆蓋的越大
        aboveCoveredLayers.orSelf(visibleRegion);

        // 可見區域要減掉該層之上的非透明區域。
        visibleRegion.subtractSelf(aboveOpaqueLayers);

上面部分的邏輯,都注釋在代碼中。繼續看~

下面是計算Layer的臟區域:

void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
        Region& outDirtyRegion, Region& outOpaqueRegion)
{
        ... ...
        // compute this layer's dirty region
        if (layer->contentDirty) {
            // we need to invalidate the whole region
            dirty = visibleRegion;
            // as well, as the old visible region
            dirty.orSelf(layer->visibleRegion);
            layer->contentDirty = false;
        } else {
            const Region newExposed = visibleRegion - coveredRegion;
            const Region oldVisibleRegion = layer->visibleRegion;
            const Region oldCoveredRegion = layer->coveredRegion;
            const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
            dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
        }
        dirty.subtractSelf(aboveOpaqueLayers);

contentDirty表示Layer的可見區域被修改了,這個是需要和layer的visibleRegion做一個與運算。確保可見的區域都能被刷新到。如果contentDirty沒有被修改,開始計算暴露出來的區域 exposedRegion。exposedRegion包含兩部分,之前被覆蓋的區域,現在暴露了,直接暴露的區域,現在也是暴露的區域。dirty的區域,就是暴露的區域,再除去上面非透明的區域。

void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
        Region& outDirtyRegion, Region& outOpaqueRegion)
{
        ... ...
        // accumulate to the screen dirty region
        outDirtyRegion.orSelf(dirty);

        // 更新之上非透明的區域,下面的Layer計算時會用到
        aboveOpaqueLayers.orSelf(opaqueRegion);

        // Store the visible region in screen space
        layer->setVisibleRegion(visibleRegion);
        layer->setCoveredRegion(coveredRegion);
        layer->setVisibleNonTransparentRegion(
                visibleRegion.subtract(transparentRegion));
    });

    outOpaqueRegion = aboveOpaqueLayers;
}

outDirtyRegion是屏幕的臟區域,它是每個Layer臟區域的合。最后將計算好的區域值設置到Layer中。outOpaqueRegion是屏幕的非透明區域。

  • setVisibleRegion 設置可見區域
  • setCoveredRegion 設置被覆蓋的區域
  • setVisibleNonTransparentRegion 設置可見的非透明區域,它是可見區域,減去透明區域。

回到rebuildLayerStacks函數~ computeVisibleRegions結束后,屏幕的臟區域得到了,每個Layer的可見區域,被覆蓋的區域,以及可見非透明區域都計算出來了。

void SurfaceFlinger::rebuildLayerStacks() {
    if (CC_UNLIKELY(mVisibleRegionsDirty)) {
        ...

        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            ... ...
            if (displayDevice->isDisplayOn()) {
                computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);

                mDrawingState.traverseInZOrder([&](Layer* layer) {
                    bool hwcLayerDestroyed = false;
                    if (layer->belongsToDisplay(displayDevice->getLayerStack(),
                                displayDevice->isPrimary())) {
                        Region drawRegion(tr.transform(
                                layer->visibleNonTransparentRegion));
                        drawRegion.andSelf(bounds);
                        if (!drawRegion.isEmpty()) {
                            layersSortedByZ.add(layer);
                        } else {
                            hwcLayerDestroyed = layer->destroyHwcLayer(
                                    displayDevice->getHwcDisplayId());
                        }
                    } else {
                        hwcLayerDestroyed = layer->destroyHwcLayer(
                                displayDevice->getHwcDisplayId());
                    }

                    if (hwcLayerDestroyed) {
                        auto found = std::find(mLayersWithQueuedFrames.cbegin(),
                                mLayersWithQueuedFrames.cend(), layer);
                        if (found != mLayersWithQueuedFrames.cend()) {
                            layersNeedingFences.add(layer);
                        }
                    }
                });
            }
            ... ...
        }
    }
}

rebuildLayerStacks函數中對Layer再遍歷一次,這次是正序,也就是從下往上。遍歷時,主要做了一下處理:

  • 計算Layer需要繪制的區域drawRegion,將Layer的可見區域和Display的大小做交集而得到
  • 如果drawRegion不為空,將該Layer加到當前Display的Layer列表中,也是按照z-order進行存放layersSortedByZ。每個Display有自己的layersSortedByZ。
  • 如果之前Layer是可見的,現在不可見,銷毀掉hwc Layer。銷毀的Layer放到layersNeedingFences中,它雖然不需要releaseFence,但是還是需要fence去釋放舊的Buffer。

rebuildLayerStacks的最后,將數據更新到Display中。

void SurfaceFlinger::rebuildLayerStacks() {
    ... ...

        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            ... ...
            displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
            displayDevice->setLayersNeedingFences(layersNeedingFences);
            displayDevice->undefinedRegion.set(bounds);
            displayDevice->undefinedRegion.subtractSelf(
                    tr.transform(opaqueRegion));
            displayDevice->dirtyRegion.orSelf(dirtyRegion);
        }
    }
}

Display中還有一個區域,叫未定義的區域。也就是屏幕的大小減去屏幕的非透明區域opaqueRegion余下的部分。

創建Layer棧完成,此時需要進行合成顯示的數據已經被更新到每個Display各自的layersSortedByZ中。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容