[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 图形系统开篇