[Android禪修之路] SurfaceFlinger 合成前的預處理
theme: channing-cyan
SurfaceFlinger 合成前的預處理
前言
之前的SurfaceFlinger 合成總覽已經把合成的整體流程羅列出來了, 從這篇開始, 我們會分別就合成的不同階段, 進行詳細的解讀。
首先是合成前的準備工作.
一 合成前
SurfaceFlinger 合成流程的全部代碼之前已經列出來了,這裏只關注合成前的部分。
1.1 handleMessageRefresh
```cpp void SurfaceFlinger::handleMessageRefresh() { mRefreshPending = false;
const bool repaintEverything = mRepaintEverything.exchange(false);
// 合成前預處理
preComposition();
// 重建Layer集合,並計算每個Layer的可見區域的髒數據
rebuildLayerStacks();
// 計算工作區間
calculateWorkingSet();
...
} ```
可以看出, SurfaceFlinger 整個合成前的準備的過程, 還是比較明朗的, 接下來我們就來詳細解讀這三部分
- preComposition:合成前的預處理
- rebuildLayerStacks:重建圖層髒區域的集合
- calculateWorkingSet:計算工作區間
對於這些函數的具體內容,我們先不做猜測,通過看具體的源碼,再來總結
二 preComposition
preComposition 就是合成前的預處理工作,我們之間看源碼
cpp
void SurfaceFlinger::preComposition()
{
mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
bool needExtraInvalidate = false;
// 遍歷圖層調用對應 Layer 的 onPreComposition
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->onPreComposition(mRefreshStartTime)) {
needExtraInvalidate = true;
}
});
// 如果有 Layer 還有未處理的 Frame (或者説發生了改變),
// 則發送一個 Invalidate 消息, 再進行一次合成和渲染操作
if (needExtraInvalidate) {
signalLayerUpdate();
}
}
首先就出現了一個 mDrawingState 對象,這個對象定義在 SurfaceFlinger.h 的頭文件中,它是一個 State 內部類,在 Layer.h 頭文件中也定義了 State,不過它是一個結構體。它們是兩個不同的 State,所以在閲讀代碼的時候不能搞混。
c
State mDrawingState{LayerVector::StateSet::Drawing};
2.1 State
```c class State { public: // LayerVector::StateSet 是 LayerVector.h 頭文件中定義的一個枚舉類,它有三個枚舉對象 // Invalid:已失效的 // Current:當前的 // Drawing:之前繪製的 // 現在我們再來看看 SurfaceFlinger 中定義的 State,它使用的枚舉對象是 Drawing,也就是之前繪製的 explicit State(LayerVector::StateSet set) : stateSet(set), layersSortedByZ(set) {} State& operator=(const State& other) { // 顯式地拷貝 State layersSortedByZ = other.layersSortedByZ; displays = other.displays; colorMatrixChanged = other.colorMatrixChanged; if (colorMatrixChanged) { colorMatrix = other.colorMatrix; } globalShadowSettings = other.globalShadowSettings; return *this; }
const LayerVector::StateSet stateSet = LayerVector::StateSet::Invalid;
// 所有參與繪製的 Layer
LayerVector layersSortedByZ;
// 所有輸出設備的對象,這個一個 map 對象,key 是一個 IBinder,值是 DisplayDeviceState
DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays;
bool colorMatrixChanged = true;
mat4 colorMatrix;
renderengine::ShadowSettings globalShadowSettings;
void traverse(const LayerVector::Visitor& visitor) const;
void traverseInZOrder(const LayerVector::Visitor& visitor) const;
void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
};
```
通過這個 mDrawingState , 我們簡單的瞭解了一些 State 這個類。
這個 mDrawingState 保存了所有需要參與繪製的 Layer , 此處會按照 Z 軸的排序取到當前需要繪製的 Layer ,然後對每個 Layer 調用其 onPreComposition 判斷其是否還有未處理的的 Frame ,如果有就將 needExtraInvalidate 置為 true ,表示需要進行額外的合成和渲染操作。
2.2 LayerVector
我們再來簡單看一下定義枚舉的 LayerVector
```c
class LayerVector : public SortedVector
LayerVector& operator=(const LayerVector& rhs);
// 對 Layer 進行排序
int do_compare(const void lhs, const void rhs) const override;
// 注意, 這裏用 Visitor 命名了一個參數説 Layer 指針, 返回值是 void 的函數
// 這個函數後續會用到
using Visitor = std::function<void(Layer*)>;
void traverseInReverseZOrder(StateSet stateSet, const Visitor& visitor) const;
void traverseInZOrder(StateSet stateSet, const Visitor& visitor) const;
private: const StateSet mStateSet; }; } ```
LayerVector 這個類也比較簡單, 不過讓人注意的一點是, 裏面有一個 StateSet 的枚舉變量, 它有三個參數, 而這三個參數基本對應着一個 Layer 的三種狀態
最後再來看一下它的父類 SortedVector
2.3 SortedVector
c
template <class TYPE>
class SortedVector : private SortedVectorImpl
{
friend class Vector<TYPE>;
public:
typedef TYPE value_type;
}
這是一個模板類, 而裏面有一個 Vector 容器, 它裝的就是需要顯示的 Layer。
2.4 signalLayerUpdate
最後再來看一下如果 preComposition 做完遍歷後的另一個操作,也就是如果 Layer 發生了改變的情況, 這裏調用了 EventQueue 的 invalidate 發送消息, 也就是將操作傳遞到了 SurfaceFlinger 中的 Handle 的消息機制。
cpp
void SurfaceFlinger::signalLayerUpdate() {
mScheduler->resetIdleTimer();
//又調用了一次 invalidate , INVALIDATE 事件之前已經分析過了
mEventQueue->invalidate();
}
到此,SurfaceFlinger 的合成前的預處理 preComposition,我們算是大概看完了,不過看完之後不僅沒有解答之前的疑惑,還出現了更多的疑惑。
首先,我們用一句話概括預處理 preComposition 所做的事情,那就是:
遍歷 mDrawingState 對象中的 Layer,調用每個 Layer 的 preComposition,這個函數會返回這個 Layer 是否發生了改變,如果發生了改變,就需要重繪,並且通過 SurfaceFlinger 的消息機制,將重繪消息傳入 EventQueue。
當然,在這個過程中,我們遇到了一些疑問:
- Layer 的 preComposition 做了哪些事:[解讀Layer]
- EventQueue 的消息隊列接收到重繪消息後又發生了什麼:[解讀SurfaceFlinger中的消息隊列]
- 這個 mDrawingState 中的 Layer 圖層,是怎樣添加進來的 這些疑問我們現在還無法解答,只能在針對這些機制的篇幅中單獨研究,等到我們看完整個 SurfaceFlinger 的工作原理後,這些我們也就知道了。
三 rebuildLayerStacks
rebuildLayerStacks 中的工作較多, 不過一句話概括就是: 重新計算所有需要繪製的 Layer 的髒區域
當然,rebuildLayerStacks 函數的邏輯較長, 這裏分為幾個部分解析
3.1 rebuildLayerStacks 的第一部分
cpp
// 重建設備的可見Layer集合,並計算每個Layer的可見區域的髒區域
void SurfaceFlinger::rebuildLayerStacks() {
// 只重建可見的髒區域
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
mVisibleRegionsDirty = false;
//將 mGeometryInvalid 置為 true ,這個值影響後續是否需要 hwc 合成
invalidateHwcGeometry();
// 針對每一個顯示設備重建可見Layer
for (const auto& pair : mDisplays) {
// mDisplays 是一個 map,它是 value 就是 DisplayDevice
const auto& displayDevice = pair.second;
//DisplayDevice 的 getCompositionDisplay ,返回一個 std::shared_ptr<compositionengine::Display>
auto display = displayDevice->getCompositionDisplay();
//Display 繼承自 Output , Output 的 getState ,返回一個 OutputCompositionState
//OutputCompositionState 是輸出的原始合成狀態數據
const auto& displayState = display->getState();
//兩個區域, opaqueRegion 是不透明區域, dirtyRegion 是髒區域
Region opaqueRegion;
Region dirtyRegion;
compositionengine::Output::OutputLayers layersSortedByZ;
Vector<sp<Layer>> deprecated_layersSortedByZ;
Vector<sp<Layer>> layersNeedingFences;
//transform 是邏輯到物理的轉換
const ui::Transform& tr = displayState.transform;
//bounds 是物理顯示屏的區域
const Rect bounds = displayState.bounds;
...
}
}
}
第一部分的代碼出現了幾個對象,關於這幾個對象這裏簡單介紹一下,具體詳細的可以看附錄1
- mDisplays: 這是 SurfaceFlinger 中保存 DisplayDevice 對象的 map 集合, 它的 key 是一個 IBinder 的弱指針, value 則是一個 DisplayDevice 指針
cpp
std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays;
- DisplayDevice: 顯示設備, Android 系統是支持多顯示器的, 而這個 DisplayDevice 則封裝了具體顯示器的顯示參數。
- compositionengine::Display:一個合成目標對象,它繼承自 Output,封裝了硬件合成器 HWC 的一些參數
我們再看一下 DisplayDevice 的創建方式, 在之前介紹 SurfaceFlinger 的啟動流程中的 init 函數中, 有這樣一行代碼。SurfaceFlinger的啟動流程
cpp
const auto display = getDefaultDisplayDeviceLocked();
顯然, 它是獲取默認的 DisplayDevice , 在一系列的調用之後, 會通過一個 token 來拿到一個 DisplayDevice
```cpp
[frameworks/native/services/surfaceflinger/SurfaceFlinger.h]
sp
// 拿到 displayId,這個 displayId 也就是它的 IBinder 的值
sp
std::optional
這裏拿到的 it 就是 map , 而 it->second 則是我們需要的 DisplayDevice. 關於 mDisplays 集合的數據來源, 這裏暫不深究, 後續單獨探究
第一部分, 主要還是定義了一些後續需要用到的對象. 接下來, 我們就看看這些對象的處理邏輯
3.2 rebuildLayerStacks 第二部分
接下來就是第二部分了,之前的第一部分主要做的就是準備一些現在需要用到的對象,而第二部分就是具體的執行
- OutputCompositionState 是輸出合成的原始數據, 如果它的 isEnabled 為 false ,則表示這個 DisplayDevice 不需要此次合成, 所以這裏就不需要執行具體的邏輯
- 然後是計算可見區域, 這也是我們常説的計算髒區域
- 接下來就是遍歷需要繪製的 Layer , 按照我們傳入的 Visitor 函數處理,關於 Visitor 的定義查看[2.2]
關於這裏出現的 DisplayDevice 和 OutputCompositionState 的詳細説明, 可以跳轉附錄1查看
```cpp //只有 OutputCompositionState 的 isEnabled 為 true 時,才會執行合成 if (displayState.isEnabled) { //計算可見區域 computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
// 遍歷所有需要繪製的 Layer
// 遍歷到的 Layer 會經過函數 Visitor 的處理
// 這個 Visitor 函數在之前的 LayerVector 中
mDrawingState.traverseInZOrder([&](Layer* layer) {
...
});
} ```
3.2.1 computeVisibleRegions
計算可見區域, 傳入的兩個參數
- dirtyRegion: 髒區域
- opaqueRegion: 不透明區域
在傳入的 Visitor 函數中, 處理了 Layer 對象, 關於 Layer 的詳細解讀, 跳轉Layer 解讀
關於 SurfaceFlinger 中可見區域的計算, 有以下規則
- 在 Android 中, 屏幕上繪製出來的圖像上多個應用相加而來的
- 上層的應用的不透明區域會遮擋住下層的應用,這部分不需要繪製
- 上層應用的透明或半透明區域遮擋住的部分, 依舊是可見的, 需要繪製
其次,再來説説 Android 中的圖層 Layer,使用用過 Photoshop 的用户應該知道,圖層的概念。軟件中的一張圖是由多個圖層疊加而來的,如果上面有一個不透明的圖層覆蓋,那麼下面的圖層將會被遮擋,也就是不可見。 在 Android 中也是一樣的,所以關於圖層區域的分類,有如下幾類
- aboveOpaqueLayers:當前 Layer 的上層 Layer 所有的不透明區域。也就是説這部分的區域是都不需要繪製的,需要從髒區域中減去
- aboveCoveredLayers:當前 Layer 的上層 Layer 所有的可見區域。
- opaqueRegion:當前 Layer 的不透明區域。(透明和半透明都不屬於不透明區域)
- visibleRegion:當前 Layer 的可見區域。這個區域是需要計算的,被上層 Layer 覆蓋的,完全透明的都需要減去。
- coveredRegion:當前 Layer 被上層 Layer 覆蓋的區域。(被透明區域覆蓋的區域也算被覆蓋區域)
- transparentRegion:完全透明的區域。(這部分區域沒有必要合成)
基於這些理解,我們再來看以下代碼
```cpp
void SurfaceFlinger::computeVisibleRegions(const sp
//std::shared_ptr<compositionengine::Display>
// 由 hwc 設備支持的顯示器合成目標,封裝了一些 hwc 相關的參數
auto display = displayDevice->getCompositionDisplay();
// 上層應用全部 Layer 的不透明區域
Region aboveOpaqueLayers;
// 上層應用全部 Layer 的被覆蓋的(可見)區域,
Region aboveCoveredLayers;
// 髒區域: 需要繪製的地方
Region dirty;
// outDirtyRegion 是要返回的繪製區域,所以這裏先清除之前遺留的數據
outDirtyRegion.clear();
// 從這裏開始遍歷,也就是説之前定義的一些變量是會隨着遍歷一直存在的,在按照 Z 軸遍歷圖層的時候
// 每遍歷到的一層都需要添加到之前定義的區域中,因為對於它下面的圖層來説,它就是上層的圖層
// 遍歷 mDrawingState 中需要繪製的 Layer,這裏傳入的是一個函數 Visitor
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
// Visitor 的入參數是 Layer 指針,這個函數就是將 Layer 按照 Z 軸的座標逆序排列
// 獲取 Layer 的 mDrawingState
const Layer::State& s(layer->getDrawingState());
// Android支持多個屏幕,layer可以定製化的只顯示到某個顯示屏幕上。其中就是靠layerStack(Layer棧)來實現的
// Layer的stack值如果和DisplayDevice的stack值一樣,説明這個layer是屬於這個顯示屏幕的
// 所以如果 Layer 不屬於此 DisplayDevice,則不顯示
if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
return;
}
//不透明區域
Region opaqueRegion;
//可見區域,屏幕上的不完全透明的區域,被半透明覆蓋的區域,部分被不透明覆蓋的區域
Region visibleRegion;
//覆蓋區域,上方被可見區域(包括半透明區域)覆蓋的表面區域
Region coveredRegion;
//完全透明的區域
Region transparentRegion;
// 通過將可見區域設置為空來處理隱藏表面
if (CC_LIKELY(layer->isVisible())) {
//isOpaque 返回 true 表示 layer 不透明,所以返回 false 時表示這個 layer 是透明的
const bool translucent = !layer->isOpaque(s);
// 這個 Layer 的需要繪製的區域,getScreenBounds 見[3.2.1.1]
Rect bounds(layer->getScreenBounds());
// 先將這個區域設置為可見區域
visibleRegion.set(bounds);
ui::Transform tr = layer->getTransform();
// 如果可見區域不為空
if (!visibleRegion.isEmpty()) {
//先判斷 layer 是否透明
if (translucent) {
//如果layer是透明的,就判斷能否做透明區域的優化
if (tr.preserveRects()) {
// 如果可以進行透明區域優化, 則執行透明區域優化
transparentRegion = tr.transform(layer->getActiveTransparentRegion(s));
} else {
// 如果 Transform 太複雜, 就不執行透明區域優化
transparentRegion.clear();
}
}
// 計算完全不透明的區域,完全不透明區域居然要系統的圓角 radius 為0
const int32_t layerOrientation = tr.getOrientation();
if (layer->getAlpha() == 1.0f && !translucent &&
layer->getRoundedCornerState().radius == 0.0f &&
((layerOrientation & ui::Transform::ROT_INVALID) == false)) {
// 如果這個區域是完全不透明的區域,就把可見區域放到完全不透明的區域中
opaqueRegion = visibleRegion;
}
}
}
// 如果可見區域是空, 就清除掉圖層上的可見區域範圍
if (visibleRegion.isEmpty()) {
layer->clearVisibilityRegions();
return;
}
// 將被覆蓋區域 = 處於上層區域中的可見區域
coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
// 將本層的可見區域添加到上層圖層的區域中, 用來處理下一個圖層
aboveCoveredLayers.orSelf(visibleRegion);
// 本層的可見區域需要減去上層應用的不透明區域
visibleRegion.subtractSelf(aboveOpaqueLayers);
// 計算圖層的髒區域
if (layer->contentDirty) {
// 如果內容需要重繪,那麼可見區域就是需要重繪的髒區域
dirty = visibleRegion;
// 將本層的髒區域添加到之前圖層的髒區域中, 也就是合成所有圖層的髒區域
dirty.orSelf(layer->visibleRegion);
// 圖層的可見區域處理了之後, 圖層就沒有髒區域了
layer->contentDirty = false;
} else {
/* 如果圖層沒有髒區域, 則計算暴露區域
* 暴露區域由兩部分組成
* 1) 現在可見並且以前被覆蓋的區域
* 2) 現在新增的暴露區域(以前這個區域區域被遮擋了)
*/
// 新暴露的區域: 可見區域間去被覆蓋的區域
const Region newExposed = visibleRegion - coveredRegion;
// 舊的可見區域即圖層的可見區域
const Region oldVisibleRegion = layer->visibleRegion;
// 舊的被覆蓋區域即圖層的被覆蓋區域
const Region oldCoveredRegion = layer->coveredRegion;
// 舊的暴露區域: 即舊的可見區域減去舊的被覆蓋的區域
const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
// (newExposed-oldExposed) 是新增的暴露區域
// (visibleRegion&oldCoveredRegion) 是新增的沒有被覆蓋的區域
// 髒區域 = 新增的沒有被覆蓋的區域 + 新增的暴露區域
dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
}
// 髒區域需要裁剪掉上層圖層的不透明區域
dirty.subtractSelf(aboveOpaqueLayers);
// 將新增的髒區域添加到返回參數中
outDirtyRegion.orSelf(dirty);
// 將本圖層不透明區域添加到上層圖層區域, 處理下一個圖層
aboveOpaqueLayers.orSelf(opaqueRegion);
//保存圖層計算區域
layer->setVisibleRegion(visibleRegion);
layer->setCoveredRegion(coveredRegion);
layer->setVisibleNonTransparentRegion(
visibleRegion.subtract(transparentRegion));
});
outOpaqueRegion = aboveOpaqueLayers;
} ```
3.2.1.1 Layer::getScreenBounds
getScreenBounds 就是獲取當前 Layer 圖層的邊界
```c [frameworks/native/services/surfaceflinger/Layer.cpp] Rect Layer::getScreenBounds(bool reduceTransparentRegion) const { if (!reduceTransparentRegion) { return Rect{mScreenBounds}; }
FloatRect bounds = getBounds();
ui::Transform t = getTransform();
// Transform to screen space.
bounds = t.transform(bounds);
return Rect{bounds};
} ```
我們看到的 getScreenBounds 沒有傳遞參數,而這裏確有一個參數,也就是説它有一個默認參數,從 Layer.h 這個頭文件中科院得知,這個默認參數是 true,也就是説 Layer 會先通過 getBounds 拿到一個 bounds,然後再對這個 bounds 進行處理,最後得到一個 Rect
c
[frameworks/native/services/surfaceflinger/Layer.h]
Rect getScreenBounds(bool reduceTransparentRegion = true) const;
3.2.1.2 Layer::getBounds
getBounds 函數做了如下操作
- 拿到 mDrawingState
- 調用 getActiveTransparentRegion拿到一個 Rect
- 調用有參數的 getBounds,參數就是 getActiveTransparentRegion 的返回值
c
[frameworks/native/services/surfaceflinger/Layer.cpp]
FloatRect Layer::getBounds() const {
const State& s(getDrawingState());
return getBounds(getActiveTransparentRegion(s));
}
3.2.1.3 Layer::getDrawingState
getDrawingState 是一個內聯函數,定義在 Layer.h 頭文件中,它返回了 Layer 對象中的 mDrawingState,mDrawingState 它是一個 State,這個 State 定義在 Layer.h 這個頭文件中,在 Layer 對象中有兩個 State
c
State mCurrentState; // 當前正在使用的 State
State mDrawingState; // 正在繪製的 State
inline const State& getDrawingState() const { return mDrawingState; }
3.2.1.4 Layer::getActiveTransparentRegion
getActiveTransparentRegion 定義在 Layer.h 頭文件中,它直接返回了 State 中的 activeTransparentRegion_legacy,activeTransparentRegion_legacy 的字面意思就是遺留的活動透明區域,按照我們之前的理解,透明的區域應該是不需要合成的,所以當前 Layer 的合成區域中,應該會減去這部分區域。
c
[frameworks/native/services/surfaceflinger/Layer.h]
virtual Region getActiveTransparentRegion(const Layer::State& s) const {
return s.activeTransparentRegion_legacy;
}
在拿到這個 Region 之後,又調用了一個 getBounds 函數,這次傳入的參數就是這個 Region
3.2.1.5 Layer::getBounds(const Region& activeTransparentRegion)
在這次的 getBounds 函數中,執行了我們上述猜測的邏輯,減去了活動透明區域。最後拿到的就是我們要合成的區域。
```c FloatRect Layer::getBounds(const Region& activeTransparentRegion) const { // 減去邊界的透明區域,獲取最後的邊界 return reduce(mBounds, activeTransparentRegion); }
```
3.2.1.6 reduce
reduce 這個函數,就是直接減去傳入參數 win 中的 exclude 區域
c
static FloatRect reduce(const FloatRect& win, const Region& exclude) {
if (CC_LIKELY(exclude.isEmpty())) {
return win;
}
return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
}
3.2.1.7 getScreenBounds 總結
getScreenBounds 這個函數就是獲取這個 Layer 的需要合成的區域,它首先會拿到當前繪製的 mDrawingState,然後拿到這個 State 的透明區域,最後再用自己的區域減去這部分透明區域,這個最終區域就是 Layer 要繪製的區域。
瞭解 getScreenBounds 的原理,再回過頭來看[3.2.1]中計算髒區域的邏輯,就很好理解了。
3.2.2 traverseInZOrder
完成了髒區域的計算之後, 還需要做一件事情, 那就是將每個圖層的當前的顯示設備進行比較, 看看當前的圖層的髒區域, 是否在顯示區域內, 如果中顯示區域內, 那麼才會繪製當前的圖層
因為 Android 是支持多顯示器多, 不同的圖層, 可能在不同的屏幕中, 而每個屏幕的顯示數據並不相同,所以每個 Display 只需要添加自己需要顯示的圖層
```cpp mDrawingState.traverseInZOrder(& { auto compositionLayer = layer->getCompositionLayer(); if (compositionLayer == nullptr) { return; }
// 先拿到顯示設備的 displayId
const auto displayId = displayDevice->getId();
sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
bool needsOutputLayer = false;
// 只有顯示設備與layerStackId匹配時才需要輸出到顯示設備中
if (display->belongsInOutput(layer->getLayerStack(),
layer->getPrimaryDisplayOnly())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
// 添加需要繪製的區域
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
// 是否需要輸出顯示
needsOutputLayer = true;
}
}
if (needsOutputLayer) {
layersSortedByZ.emplace_back(
display->getOrCreateOutputLayer(displayId, compositionLayer,
layerFE));
// 如果需要輸出顯示, 就添加到 deprecated_layersSortedByZ 中, 後面添加到顯示設備中
deprecated_layersSortedByZ.add(layer);
auto& outputLayerState = layersSortedByZ.back()->editState();
outputLayerState.visibleRegion =
tr.transform(layer->visibleRegion.intersect(displayState.viewport));
} else if (displayId) {
// 對於從 HWC 顯示中刪除的,並且有入隊幀的 Layer
bool hasExistingOutputLayer =
display->getOutputLayerForLayer(compositionLayer.get()) != nullptr;
bool hasQueuedFrames = std::find(mLayersWithQueuedFrames.cbegin(),
mLayersWithQueuedFrames.cend(),
layer) != mLayersWithQueuedFrames.cend();
if (hasExistingOutputLayer && hasQueuedFrames) {
// 如果滿足以上兩種情況,就將它們添加到 layersNeedingFences 列表中,這個列表就是用來設置 Fence 同步機制的
layersNeedingFences.add(layer);
}
}
}); ```
對於這部分邏輯,首先是判斷髒區域要顯示到那個顯示設備中,如果髒區域屬於該顯示設備,就將它添加進去。
對於另外一部分邏輯就不容易讓人理解,它涉及到 hwc 和 Fence 機制,這部分只能後面再看了。
3.3 rebuildLayerStacks 的第三部分
```cpp display->setOutputLayersOrderedByZ(std::move(layersSortedByZ)); // 往顯示設備中添加需要顯示的圖層 displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ); // 設置圖層的 Fence 信號 displayDevice->setLayersNeedingFences(layersNeedingFences);
Region undefinedRegion{bounds}; undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
display->editState().undefinedRegion = undefinedRegion; display->editState().dirtyRegion.orSelf(dirtyRegion); ```
這部分代碼就是將之前圖層計算的一些結果保存到顯示設備中,到這裏,重建圖層髒區域的集合就已經完成了,最後再簡單總結一下
- 圖層髒區域集合的計算首先會按 Z 軸的排序遍歷圖層 Layer
- 對於遍歷中的 Layer 會分別計算它的可見區域和之前所有圖層的不透明區域和被覆蓋的區域
- 當前圖層的 Layer 需要減去之前所有圖層覆蓋的區域和活動中的透明區域等等,最後拿到的區域才是可見區域
- 拿到可見區域後會計算這個可見區域的髒區域,並將它添加到遍歷圖層的總髒區域的集合中,當前的圖層也會添加到所有圖層的覆蓋區域和不透明的區域中,用於計算後面的圖層
- 計算完的需要需要判斷它屬於那個顯示設備,添加到對應的顯示設備中
- hwc 處理的需要添加 Fence 同步機制
- 遍歷完成後的結果需要保存到對應的顯示設備中
四 calculateWorkingSet
- 這裏首先會遍歷所有的顯示設備, 然後根據不同的顯示設備處理對應的圖層
- 對於圖層的處理主要是更新了圖層的合成狀態
- 最後將圖層的數據寫入, setPerFrameData 這個方法不同的圖層有不同的實現, 詳情查看[Layer 解讀]
```cpp //hwcomposer的設定,將Layer數據更新給HWC void SurfaceFlinger::calculateWorkingSet() {
// mGeometryInvalid 已經在 rebuildLayerStacks 中修改為了 true,見[3.1]
if (CC_UNLIKELY(mGeometryInvalid)) {
mGeometryInvalid = false;
//mDisplays 是一個 map ,定義如下
//std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays;
// 根據不同的顯示設備做處理
for (const auto& [token, displayDevice] : mDisplays) {
//返回一個 std::shared_ptr<compositionengine::Display>
//compositionengine::Display 是由hardware的顯示設備組合來的,封裝了 hwc 相關的一些參數
auto display = displayDevice->getCompositionDisplay();
uint32_t zOrder = 0;
// 拿到了不同的顯示設備, 然後處理每個顯示設備中的圖層
//將這些 display 中的 layer 按照 Z 軸的順序進行處理
for (auto& layer : display->getOutputLayersOrderedByZ()) {
//這個 layer 是 OutputLayer, 獲取的是 OutputCompositionState
// 首先是拿到圖層的合成狀態
auto& compositionState = layer->editState();
//forceClientComposition 指強制 GPU 合成(Client)
//如果為 true ,將在此輸出上使用客户端組合,即 OpenGL ES 合成,如果為 false 則為 hwc 合成
compositionState.forceClientComposition = false;
if (!compositionState.hwc || mDebugDisableHWC || mDebugRegion) {
compositionState.forceClientComposition = true;
}
// 設置 Z 軸順序
compositionState.z = zOrder++;
//更新圖層的合成狀態
layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
true);
// 重新計算OutputLayer的幾何狀態
// 比如根據顯示屏全局矩陣調整該Layer的DisplayFrame、
// 變換窗口裁剪以匹配緩衝區座標系等等。
layer->updateCompositionState(true);
// 將Layer更新完畢的幾何狀態寫入HWC
layer->writeStateToHWC(true);
}
}
}
// 設置每幀數據
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
if (!displayId) {
continue;
}
auto* profile = display->getDisplayColorProfile();
//顏色矩陣
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
}
//色彩模式
Dataspace targetDataspace = Dataspace::UNKNOWN;
if (useColorManagement) {
ColorMode colorMode;
RenderIntent renderIntent;
pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
display->setColorMode(colorMode, targetDataspace, renderIntent);
}
//遍歷可見的Layer
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
//根據layer的數據空間 dataSpace 來設置layer的合成方式
if (layer->isHdrY410()) {
layer->forceClientComposition(displayDevice);
} else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
!profile->hasHDR10Support()) {
layer->forceClientComposition(displayDevice);
} else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
!profile->hasHLGSupport()) {
layer->forceClientComposition(displayDevice);
}
if (layer->getRoundedCornerState().radius > 0.0f) {
layer->forceClientComposition(displayDevice);
}
if (layer->getForceClientComposition(displayDevice)) {
layer->setCompositionType(displayDevice,
Hwc2::IComposerClient::Composition::CLIENT);
continue;
}
// 設置每幀的數據
const auto& displayState = display->getState();
// 這裏的 setPerFrameData ,對於不同的 Layer 有不同的實現方式,
// 比如 ColorLayer 和 BufferLayer 的實現方式就不同
// 具體的可以查看 Layer 詳解
layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
displayDevice->getSupportedPerFrameMetadata(),
isHdrColorMode(displayState.colorMode) ? Dataspace::UNKNOWN
: targetDataspace);
}
}
mDrawingState.colorMatrixChanged = false;
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
// 設置 layerState 的合成方式
layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
layer->getCompositionType(displayDevice));
}
}
} ```
calculateWorkingSet 的函數比較長,這裏就不進行拆分了,還是簡單總結一些
- calculateWorkingSet 中有三個循環,他們都是對 mDisplays 這個 map 進行遍歷
- 第一次循環是拿到每個 DisplayDevice 的 compositionengine::Display,這裏面封裝了 hwc 的一些參數
- 按照 Z 軸的排序遍歷 compositionengine::Display 裏面的圖層,並且判斷它們是否需要使用客户端合成,並保存對應的字段到 compositionState.forceClientComposition。client 是相對 hwc 而言的,指的是使用 CPU 進行合成,即 OpenGL ES 合成。與之對應的是 hwc 合成,即使用 GPU 進行合成。
- 第二次循環是設置顯示設備的參數和 Layer 的合成參數,並調用 setPerFrameData 將對應的數據保存到 Layer 中
- 第三個循環就是遍歷 DisplayDevice 中的 layer,並且將它的合成方式保存到 layerState.compositionType 字段
總的來説,calculateWorkingSet 就是判斷 Layer 的合成方式,並設置數據。當然具體到 Layer 的是如何操作,還是需要看 Layer,這部分查詢[解讀Layer]
五 beginFrame 和 prepareFrame
5.1 beginFrame
beginFrame 做了合成前的一些判斷, 判斷是否本次需要重新合成, 那麼什麼情況下本次才需要重新合成呢?
- 首先本次合成要有髒區域, 如果本次連髒區域都沒有了, 那麼自然不需要合成
- 如果有髒區域, 那麼只存在一種情況不需要合成, 其他情況都需要合成
- 不需要合成的情況就是: 本次的可見圖層為空, 且上次合成的時候, 可見圖層也是空
```cpp
void SurfaceFlinger::beginFrame(const sp
// 是否有髒區域
bool dirty = !display->getDirtyRegion(false).isEmpty();
// Z 軸的可見圖層是否為空
bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
//上次合成是否有 Z 軸的可見圖層
bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
// 如果有髒區域,那麼除非本次可見圖層為空,且上次可見圖層也為空才不會合成
// 其他情況下, 都需要進行合成操作
bool mustRecompose = dirty && !(empty && wasEmpty);
const char flagPrefix[] = {'-', '+'};
static_cast<void>(flagPrefix);
// 傳遞是否需要合成
display->getRenderSurface()->beginFrame(mustRecompose);
if (mustRecompose) {
// 將本次合成是否有可見圖層保存到 lastCompositionHadVisibleLayers 中
display->editState().lastCompositionHadVisibleLayers = !empty;
}
} ```
這裏調用了 display->getRenderSurface()->beginFrame(mustRecompose)
, 這裏 getRenderSurface 拿到的其實是它對應的 Surface
5.2 prepareFrame
```cpp
void SurfaceFlinger::prepareFrame(const sp
if (!displayState.isEnabled) {
return;
}
// 調用 FramebufferSurface 的 prepareFrame
status_t result = display->getRenderSurface()->prepareFrame();
}
status_t FramebufferSurface::prepareFrame(CompositionType /compositionType/) { return NO_ERROR; } ```
prepareFrame 函數更加簡單,只是調用了 FramebufferSurface 的 prepareFrame 。
最後我們看一下這個 FramebufferSurface 在準備階段做了怎樣的處理
六 FramebufferSurface
出乎意料的是,它居然什麼都沒有做
```cpp status_t FramebufferSurface::beginFrame(bool /mustRecompose/) { return NO_ERROR; }
status_t FramebufferSurface::prepareFrame(CompositionType /compositionType/) { return NO_ERROR; } ```
到此,合成之前的工作基本就已經分析完了,最後再做一個總結。
總結
SurfaceFlinger 合成前做了以下工作
- preComposition 合成前預處理,它其實就是調用圖層的 onPreComposition ,不同圖層的具體實現不同,詳情見[Layer 解讀]。
- rebuildLayerStacks 重新計算髒區域,因為 Android 是支持多個顯示設備的,所以它會根據不同的顯示設備進行分別處理。其中最主要的就是計算可見區域 computeVisibleRegions 。
- calculateWorkingSet 計算工作區間,根據髒區域來處理圖層,然後 setPerFrameData 設置幀數據,根據不同的圖層它有不同的實現,詳情見[Layer 解讀]。
- 最後的掃尾工作 beginFrame 和 prepareFrame
- 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 圖形系統開篇