[Android禪修之路] SurfaceFlinger合成總覽
theme: channing-cyan
SurfaceFlinger合成總覽
一 概述
SurfaceFlinger 所做的最主要的工作, 就是圖元的合成和顯示, 這所做的一切都是由系統的 Vsync 信號控制的, 關於 Vsync 信號本篇暫不研究, 本篇會對 SurfaceFlinger 接收到刷新的消息後的具體處理邏輯展開説明,這也是 SurfaceFlinger 的合成引擎所做的最主要的事情。
首先,還是從我們最熟悉的界面刷新開始説起。如果我們的手機想要刷新,會執行什麼邏輯呢,因為刷新的觸發邏輯和 Vsync 相關,所以我們這裏直接看 SurfaceFlinger 接收到刷新消息之後的執行邏輯。
二 SurfaceFlinger的消息處理
首先,我們看 SurfaceFlinger 的消息處理函數 onMessageReceived,這裏只有兩種消息類型,所以邏輯也比較簡單。
- INVALIDATE:重繪消息
- REFRESH:刷新消息
cpp
[frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
/**
* SurfaceFlinger收到消息後的處理邏輯
* 主要消息有INVALIDATE和REFRESH
*/
void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
//處理INVALIDATE事件
...
break;
}
case MessageQueue::REFRESH: {
//處理REFRESH事件
handleMessageRefresh();
break;
}
}
}
這兩個事件我們都比較熟悉,一個是 INVALIDATE 的重繪事件,一個是 REFRESH 的刷新事件,其中 INVALIDATE 事件最後還是會引發 REFRESH 事件,所以為了瀏覽整個流程, 我們先從 INVALIDATE 事件開始看起
2.1 SurfaceFlinger的INVALIDATE事件
```cpp //SurfaceFlinger INVALIDATE事件的邏輯 case MessageQueue::INVALIDATE: { //首先判斷是否丟幀 bool frameMissed = previousFrameMissed(); //記錄具體的丟幀原因 bool hwcFrameMissed = mHadDeviceComposition && frameMissed; bool gpuFrameMissed = mHadClientComposition && frameMissed; if (frameMissed) { mFrameMissedCount++; mTimeStats->incrementMissedFrames(); } if (hwcFrameMissed) { mHwcFrameMissedCount++; } if (gpuFrameMissed) { mGpuFrameMissedCount++; } //丟幀的邏輯結束後,調用updateFpsBasedOnContent if (mUseSmart90ForVideo) { //這個是Fps視頻檢測功能 mScheduler->updateFpsBasedOnContent(); } if (performSetActiveConfig()) { break; }
//如果丟幀,則不處理此次VSYNC
if (frameMissed && mPropagateBackpressure) { if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) { signalLayerUpdate(); break; } } //調用Vr顯示 updateVrFlinger(); //調用handleMessageTransaction bool refreshNeeded = handleMessageTransaction(); //調用handleMessageInvalidate refreshNeeded |= handleMessageInvalidate(); updateCursorAsync(); updateInputFlinger(); refreshNeeded |= mRepaintEverything; if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) { //如果事務修改了窗口狀態、新緩衝區被鎖存或 HWC 已請求完全重繪,則發出刷新信號 signalRefresh(); } break; } ```
到此, 我們可以瀏覽整個 INVALIDATE 事件的流程, 發現最後它還是會執行刷新的邏輯, 只不過中執行刷新邏輯之前, 做了兩件比較重要的事情 * handleMessageTransaction * handleMessageInvalidate
三 刷新之前的工作
3.1 handleMessageTransaction
handleMessageTransaction 實際上就是調用了 handleTransaction 進行事務的處理。
cpp
bool SurfaceFlinger::handleMessageTransaction() {
//peekTransactionFlags 函數是拿到 mTransactionFlags,這個標誌會在接收到一些事務的時候發生改變
uint32_t transactionFlags = peekTransactionFlags();
bool flushedATransaction = flushTransactionQueues();
bool runHandleTransaction = transactionFlags &&
((transactionFlags != eTransactionFlushNeeded) || flushedATransaction);
// 先看是否有需要處理的事務,如果有的話就執行 handleTransaction
// 如果沒有調用 eTransactionFlushNeeded 修改 mTransactionFlags 的值
if (runHandleTransaction) {
handleTransaction(eTransactionMask);
} else {
getTransactionFlags(eTransactionFlushNeeded);
}
// 如果 mTransactionQueues 不為空,就需要需要處理事務,修改 mTransactionFlags 的值
if (transactionFlushNeeded()) {
setTransactionFlags(eTransactionFlushNeeded);
}
return runHandleTransaction;
}
bool SurfaceFlinger::transactionFlushNeeded() {
return !mTransactionQueues.empty();
}
我們先看具體處理事務的邏輯。
3.1.1 handleTransaction
cpp
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
// 用 mDrawingState 創建一個副本 drawingState
State drawingState(mDrawingState);
Mutex::Autolock _l(mStateLock);
mDebugInTransaction = systemTime();
mVsyncModulator.onTransactionHandled();
transactionFlags = getTransactionFlags(eTransactionMask);
// 調用 handleTransactionLocked 這個是真正處理事務的函數
handleTransactionLocked(transactionFlags);
mDebugInTransaction = 0;
invalidateHwcGeometry();
}
3.1.2 handleTransactionLocked
handleTransactionLocked 這段代碼很長,但是核心邏輯就只有兩塊
- 圖層是否發生了改變
- 顯示設備是否發生了改變
針對以上兩塊邏輯,它對圖層進行了遍歷,判斷了圖層的屬性是否變化,並判斷了圖層所屬的顯示設備是否在 mDisplays 集合中,最後處理了被移除的圖層,然後提交了事務。
cpp
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
// 通知所有的圖層有可用幀
mCurrentState.traverseInZOrder([](Layer* layer) {
layer->notifyAvailableFrames();
});
// 遍歷子對象(如果需要,為每個子對象執行事務)
if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) {
mCurrentState.traverseInZOrder([&](Layer* layer) {
// 獲取圖層的 TransactionFlags
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) return;
// 調用圖層的 doTransaction
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
// 如果返回的值是需要計算可見區域,那麼 mVisibleRegionsDirty 就設為 true
mVisibleRegionsDirty = true;
if (flags & Layer::eInputInfoChanged) {
mInputInfoChanged = true;
}
});
mTraversalNeededMainThread = false;
}
// 如果需要,執行顯示自己的事務
if (transactionFlags & eDisplayTransactionNeeded) {
processDisplayChangesLocked();
processDisplayHotplugEventsLocked();
}
// 如果顯示設備發生了改變或者有顯示設備的事務需要處理
if (transactionFlags & (eDisplayLayerStackChanged|eDisplayTransactionNeeded)) {
sp<const DisplayDevice> hintDisplay;
uint32_t currentlayerStack = 0;
bool first = true;
mCurrentState.traverseInZOrder([&](Layer* layer) {
// layerStack 是一個 uint32_t 的值,它表示當前的圖層關聯的圖層堆棧
uint32_t layerStack = layer->getLayerStack();
if (first || currentlayerStack != layerStack) {
// 如果是第一個圖層,或者是遍歷時 Layer 的圖層堆棧並不相同
currentlayerStack = layerStack;
// 確定此layerstack是否已鏡像(多個顯示)。如果是鏡像就選擇默認顯示;如果不是鏡像就選擇唯一顯示。
hintDisplay = nullptr;
for (const auto& [token, display] : mDisplays) {
if (display->getCompositionDisplay()
->belongsInOutput(layer->getLayerStack(),
layer->getPrimaryDisplayOnly())) {
if (hintDisplay) {
hintDisplay = nullptr;
break;
} else {
hintDisplay = display;
}
}
}
}
if (!hintDisplay) {
// 這裏是一段修復bug的代碼
// 當該層使用在任何顯示器上都不可見的 layerStack 時,可能為空。可能在屏幕關閉/打開時發生
hintDisplay = getDefaultDisplayDeviceLocked();
}
if (hintDisplay) {
layer->updateTransformHint(hintDisplay);
}
first = false;
});
}
// 如果需要,執行我們自己的交易
if (mLayersAdded) {
mLayersAdded = false;
mVisibleRegionsDirty = true;
}
// 對於某些圖層已被刪除,需要更新它們所在的可見區域
if (mLayersRemoved) {
mLayersRemoved = false;
mVisibleRegionsDirty = true;
mDrawingState.traverseInZOrder([&](Layer* layer) {
// 屬於刪除圖層
if (mLayersPendingRemoval.indexOf(layer) >= 0) {
// 刪除不可見的圖層
Region visibleReg;
visibleReg.set(layer->getScreenBounds());
invalidateLayerStack(layer, visibleReg);
}
});
}
// 提交事務
commitInputWindowCommands();
commitTransaction();
}
3.1.3 提交事務
提交事務有兩個函數,commitInputWindowCommands 和 commitTransaction
commitInputWindowCommands
cpp
[frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
void SurfaceFlinger::commitInputWindowCommands() {
mInputWindowCommands = mPendingInputWindowCommands;
mPendingInputWindowCommands.clear();
}
commitInputWindowCommands 這個函數就是做了一個指令的賦值。
commitTransaction
cpp
void SurfaceFlinger::commitTransaction()
{
// 先移除待移除的圖層
if (!mLayersPendingRemoval.isEmpty()) {
// 通知刪除的圖層不要進行繪製
for (const auto& l : mLayersPendingRemoval) {
recordBufferingStats(l->getName().string(),
l->getOccupancyHistory(true));
// 確保釋放設置為在任何顯示設備上的所有緩衝區
if (l->isRemovedFromCurrentState()) {
latchAndReleaseBuffer(l);
}
// 如果該層已被刪除且沒有父層,則在屏幕上遍歷層時將無法訪問該層。
// 將圖層添加到 offscreenLayers 集合中,以確保可以將其當前狀態複製到繪圖狀態。
if (!l->getParent()) {
mOffscreenLayers.emplace(l.get());
}
}
mLayersPendingRemoval.clear();
}
// 如果此事務是窗口動畫的一部分,那麼我們合成的下一幀也應視為動畫
mAnimCompositionPending = mAnimTransactionPending;
withTracingLock([&]() {
// 切換顯示狀態,將當前的狀態賦值給繪圖的狀態
mDrawingState = mCurrentState;
// 清楚改變的標記
mCurrentState.colorMatrixChanged = false;
mDrawingState.traverseInZOrder([&](Layer* layer) {
layer->commitChildList();
// 如果在遍歷 mDrawingState 時可以到達該層,則該層不再是屏幕外的。從offscreenLayer集合中刪除該層
if (mOffscreenLayers.count(layer)) {
mOffscreenLayers.erase(layer);
}
});
commitOffscreenLayers();
});
mTransactionPending = false;
mAnimTransactionPending = false;
mTransactionCV.broadcast();
}
3.2 handleMessageInvalidate
cpp
bool SurfaceFlinger::handleMessageInvalidate() {
//調用 handlePageFlip,返回是否需要刷新
bool refreshNeeded = handlePageFlip();
if (mVisibleRegionsDirty) {
//計算 Layer 的邊界
computeLayerBounds();
}
// 在 handlePageFlip 中加進去的圖層
for (auto& layer : mLayersPendingRefresh) {
Region visibleReg;
visibleReg.set(layer->getScreenBounds());
invalidateLayerStack(layer, visibleReg);
}
mLayersPendingRefresh.clear();
return refreshNeeded;
}
3.2.1 computeLayerBounds
cpp
void SurfaceFlinger::computeLayerBounds() {
for (const auto& pair : mDisplays) {
const auto& displayDevice = pair.second;
const auto display = displayDevice->getCompositionDisplay();
for (const auto& layer : mDrawingState.layersSortedByZ) {
if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
continue;
}
layer->computeBounds(displayDevice->getViewport().toFloatRect(), ui::Transform());
}
}
}
這裏調用了 Layer 的 computeBounds 來計算它的邊界。
3.2.2 handlePageFlip
handlePageFlip 的字面意思就是翻頁,它實際上就是看看新的一頁有哪些數據需要處理(測量,重繪等等),並返回一個布爾變量來決定後續是否需要刷新。
cpp
// 從各 Layer 的 BufferQueue 拿到最新的緩衝數據,並根據內容更新髒區域
bool SurfaceFlinger::handlePageFlip()
{
nsecs_t latchTime = systemTime();
bool visibleRegions = false;
bool frameQueued = false;
bool newDataLatched = false;
// 存儲需要更新的Layer,當緩衝區被鎖存時,這個集合不能改變,因為這可能導致死鎖。
mDrawingState.traverseInZOrder([&](Layer* layer) {
// 返回 layer 是否有準備好的幀
if (layer->hasReadyFrame()) {
frameQueued = true;
nsecs_t expectedPresentTime;
expectedPresentTime = mScheduler->expectedPresentTime();
// 如果有了準備好的幀,還需要判斷這個幀是否需要當前顯示,
// Layer 會根據當前幀的時間還有自己期望的顯示時間來判斷自己當前是否需要顯示準備好的幀
if (layer->shouldPresentNow(expectedPresentTime)) {
// 如果需要顯示,就把這個圖層添加進隊列中
mLayersWithQueuedFrames.push_back(layer);
} else {
// 如果沒有準備好,或者不需要當前顯示,就不做顯示邏輯
layer->useEmptyDamage();
}
} else {
layer->useEmptyDamage();
}
});
// 如果需要顯示的隊列不為空
if (!mLayersWithQueuedFrames.empty()) {
Mutex::Autolock lock(mStateLock);
for (auto& layer : mLayersWithQueuedFrames) {
// 每次重新繪製屏幕時調用 latchBuffer,並返回是否需要重新計算可見區域
//(這是一個相當繁重的操作,因此只有在需要時才應設置)。通常,這用於確定 Surface 的內容或大小是否已更改
if (layer->latchBuffer(visibleRegions, latchTime)) {
// 如果需要重新計算,就將圖層添加進 mLayersPendingRefresh 集合中
mLayersPendingRefresh.push_back(layer);
}
layer->useSurfaceDamage();
if (layer->isBufferLatched()) {
newDataLatched = true;
}
}
}
mVisibleRegionsDirty |= visibleRegions;
//如果我們需要在未來某個時間喚醒以處理不應在此 vsync 週期內顯示的排隊幀,請在下一個 vsync 週期喚醒以再次檢查。
if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
// 傳遞圖層的重繪事件
signalLayerUpdate();
}
// 如果是 BOOTLOADER,就啟動 Boot 動畫
if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) {
mBootStage = BootStage::BOOTANIMATION;
}
// 僅在確實有新工作要做時才需要繼續刷新
return !mLayersWithQueuedFrames.empty() && newDataLatched;
}
void SurfaceFlinger::signalLayerUpdate() {
mScheduler->resetIdleTimer();
mEventQueue->invalidate();
}
四 handleMessageRefresh
最後終於到了 handleMessageRefresh,就是 SurfaceFlinger 做的正式的刷新工作了。雖然説是刷新,但是它依然分了幾個階段進行
- SurfaceFlinger 合成前的預處理
- SurfaceFlinger 合作中的工作
- SurfaceFlinger 合成後的掃尾工作
關於這三個部分,之後再詳細説明,這裏就先簡單看一下代碼。
```cpp void SurfaceFlinger::handleMessageRefresh() { mRefreshPending = false; const bool repaintEverything = mRepaintEverything.exchange(false); // 合成前預處理 preComposition(); // 重建Layer集合,並計算每個Layer的可見區域的髒數據 rebuildLayerStacks(); // 計算工作區間 calculateWorkingSet();
for (const auto& [token, display] : mDisplays) { beginFrame(display); prepareFrame(display); doDebugFlashRegions(display, repaintEverything); // 合成中的工作 doComposition(display, repaintEverything); } // 合成後的工作 logLayerStats(); postFrame(); postComposition(); mHadClientComposition = false; mHadDeviceComposition = false; for (const auto& [token, displayDevice] : mDisplays) { auto display = displayDevice->getCompositionDisplay(); const auto displayId = display->getId(); mHadClientComposition = mHadClientComposition || getHwComposer().hasClientComposition(displayId); mHadDeviceComposition = mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId); } mVsyncModulator.onRefreshed(mHadClientComposition); mLayersWithQueuedFrames.clear(); } ```
五 總結
SurfaceFlinger 的合成工作極其複雜,本篇本來只是打算簡單的介紹一下 SurfaceFlinger 的合成流程,沒有想到就介紹幾個合成前的函數,篇幅就已經不少了,之後 SurfaceFlinger 的具體合成過程涉及到的東西只會更多。
最後還是做一個簡單的總結
- SurfaceFlinger 會通過它的消息回調來接收兩種事務,它們分別是 INVALIDATE 和 REFRESH,而 INVALIDATE 事件最後還是會走到 REFRESH 事件的邏輯。
- 在 INVALIDATE 中 SurfaceFlinger 會遍歷所有的圖層,判斷哪些圖層需要重新測量,哪些圖層需要刷新,並判斷圖層的改變和顯示設備的改變,最後調用 handlePageFlip 來決定是否需要刷新
- handleMessageRefresh 是 SurfaceFlinger 的刷新邏輯
- Activity啟動源碼解析(Android12)
- 從MediaServer看Binder的使用方式(一)
- 從MediaServer看Binder的使用方式(二)
- [Android禪修之路] 解讀Layer
- [Android禪修之路] Android圖形系統,從Activity到Surface
- [Android禪修之路] 解讀 GraphicBuffer 之 Framework 層
- [Android禪修之路] 解讀SurfaceFlinger中的BufferQueue
- [Android禪修之路] SurfaceFlinger 合成中的工作
- [Android禪修之路] SurfaceFlinger 中的一些對象
- [Android禪修之路] SurfaceFlinger 合成前的預處理
- [Android禪修之路] SurfaceFlinger合成總覽
- [Android禪修之路] SurfaceFlinger的啟動過程
- [Android禪修之路] Android 圖形系統開篇