上一篇我们主要分析了计算Layer的脏区域流程,其中涉及了Buffer状态迁移的后两个步骤:ACQUIRED、RELEADED。本届开始就是正式的合成步骤——REFRESH。但是这个步骤比较复杂,所以先分析合成前的准备工作:重建Layer栈与初始化硬件合成器。
合成准备
当Vsync到来时候,SF会处理MessageQueue的INVALIDATE消息,消息最后一部再次触发REFRESH消息,进入合成阶段。
这个流程在SF的handleMessageRefresh函数,位于frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp中:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
/*调Layer的onPreComposition方法,主要是标志一下Layer已经被用于合成*/
preComposition();
/*若Layer的位置/先后顺序/可见性发生变化,重新计算Layer的目标合成区域和先后顺序*/
rebuildLayerStacks();
/*配置硬件合成器,调hwc的prepare方法*/
setUpHWComposer();
/*当打开开发者选项中的“显示Surface刷新”时,额外为产生变化的图层绘制闪烁动画*/
doDebugFlashRegions();//ignore
/*执行合成主体,对3D合成而言,调opengl的drawcall,对硬件合成而言,调hwc的set方法*/
doComposition();
/*主要用于调试,调Layer的onPostComposition方法*/
postComposition();
}
这个函数每一步的功能都很清晰,看起来简单粗暴。综合上面几节,流程图如下:
每一部的功能,我们会在接下来每一步详细分析。
流程分析
preComposition
调Layer的onPreComposition方法,主要是标志一下Layer已经被用于合成。我们看看preComposition函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14void SurfaceFlinger::preComposition()
{
bool needExtraInvalidate = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
if (layers[i]->onPreComposition()) {
needExtraInvalidate = true;
}
}
if (needExtraInvalidate) {
signalLayerUpdate();
}
}
代码很简单,一共就三步:
1)获取全部经过z-order排序的layer;
2)每个layer调用onPrecomposition判断是否需要触发vsync更新;
3)Layer update。
我们看看第二步的判断逻辑,Layer的onPrecomposition函数,位于frameworks/native/services/surfaceflinger/Layer.cpp:1
2
3
4
5
6
bool Layer::onPreComposition() {
mRefreshPending = false;//标志一下Layer已经被用于合成
//当layer里存放被queue的frame以后,就会出发layer update
return mQueuedFrames > 0 || mSidebandStreamChanged;
}
我们在Android SurfaceFlinger 学习之路(八)—-Surface管理图形缓冲区中讲过,当Buffer被queue回BufferQueue,状态迁移到QUEUED,就会回调Layer的onFrameAvailable函数,将mQueuedFrames自动+1。所以当vsync到来时候,就会根据这个判断时候更新layer。
rebuildLayerStacks
若Layer的位置/先后顺序/可见性发生变化,重新计算Layer的目标合成区域和先后顺序。我们要看看rebuildLayerStacks函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55void SurfaceFlinger::rebuildLayerStacks() {
// rebuild the visible layer list per screen
//系统显示屏以及各个应用程序窗口的属性变化时
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
ATRACE_CALL();
mVisibleRegionsDirty = false;
//将mHwWorkListDirty 标记为true
invalidateHwcGeometry();
//获取当前应用程序所有按照z-order排列的layer
const LayerVector& layers(mDrawingState.layersSortedByZ);
//遍历每一个显示屏
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
Region opaqueRegion;//全局不透明区域
Region dirtyRegion;//需要重新render的脏区域
Vector< sp<Layer> > layersSortedByZ;
const sp<DisplayDevice>& hw(mDisplays[dpy]);
const Transform& tr(hw->getTransform());
const Rect bounds(hw->getBounds());
if (hw->isDisplayOn()) {
//计算当前显示屏各个应用程序的可见区域
SurfaceFlinger::computeVisibleRegions(layers,
hw->getLayerStack(), dirtyRegion, opaqueRegion);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(layers[i]);
const Layer::State& s(layer->getDrawingState());
if (s.layerStack == hw->getLayerStack()) {
//可见不透明的区域
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
//添加进入z-order排列的layer
layersSortedByZ.add(layer);
}
}
}
}
//z-order排列的layer
hw->setVisibleLayersSortedByZ(layersSortedByZ);
//显示屏大小
hw->undefinedRegion.set(bounds);
//减去不透明区域
hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
//累加脏区域
hw->dirtyRegion.orSelf(dirtyRegion);
}
}
}
void SurfaceFlinger::invalidateHwcGeometry()
{
mHwWorkListDirty = true;
}
流程如下:
1)从上一节的内容可以知道,当SurfaceFlinger服务在处理系统显示屏以及各个应用程序窗口的属性变化时,如果发现需要重新计算各个应用程序窗口的可见区域,那么就会将SurfaceFlinger类的成员变量mVisibleRegionsDirty的值设置为true。
进入判断逻辑之后,将成员变量mVisibleRegionsDirty的值设置为false了,因为这时候系统中各个应用程序窗口的可见区域开始计算了。
2)函数接下来通过SurfaceFlinger类的成员变量mDrawingState所描述的一个State对象的成员变量layersSortedByZ来获得系统当前所有的应用程序窗口,并且保存在一个类型为LayerVector的向量layers中。
3)SurfaceFlinger类的成员函数computeVisibleRegions在计算完成各个应用程序窗口的可见区域之后,会得到一个全局不透明区域,保存在输出参数opaqueRegion中。这个全局不透明区域就是接下来需要渲染的,一般情况下,它的大小就应该等于显示屏的大小,即变量hw->getBounds()所描述的区域。在异常情况下,可能会导致显示屏区域bounds大于全局不透明区域opaqueRegion,这时候前者减去后者就可以得到一些称为“虫洞”的区域。由于这些虫洞区域不会被各个应用程序窗口覆盖,因此,SurfaceFlinger服务需要对它们进行特殊处理,即以一种特殊的方式来渲染它们。在后面的部分内容中,我们就会看到SurfaceFlinger服务是通过调用SurfaceFlinger类的成员函数drawWormhole来渲染这些虫洞的。
4)dirtyRegion是需要被刷新的。 opaqueRegion 不透明区域,layer是按Z-order排序的,左右排在前面的opaqueRegion 会挡住后面的layer。Region drawRegion(tr.transform( layer->visibleNonTransparentRegion));程序需要进一步得出每个layer 绘制的区域。
5)将结果保存到hw中。
所以上述流程的重点就是computeVisibleRegions就算过程,我们详细分析这个流程。
再计算可见区域之前,我们要了解一些概念。
相关区域概述
在分析源码前,我们自己先来想一下,图层中什么样的区域是可见的呢?
- Z-order
layer的z-order无疑是第一考虑的要素。因为排在越前面的图层,其获得曝光的机率越大,可见的区域也可能越大,如下图所示:
所以在计算可见性时,是按照Z-order由上而下进行的。假如一个layer的某个区域被确定为可见,那么与之相对应的它下面的所有图层区域都会被遮盖而不可见。
- 透明度
虽然越前面的layer优先级越高,但这并不代表后面的图层完全没有机会。只要前一个layer不是完全不透明的,那么从理论上来讲用户就应该能“透过”这部分区域看到后面的内容。 - 图层大小
与透明度一样,图层大小也直接影响到其可见区域。因为每个layer都是有大有小的,即便前一个layer是完全不透明的,但只要它的尺寸没有达到“满屏”,那么比它z-order小的图层还是有机会暴露出来的。这也是我们需要考虑的因素之一。
因此我们要我们首先解释一些与应用程序窗口相关的概念:可见区域(Visible Region)、透明区域(Transparent Region)、半透明区域(Translucent Region)、完全不透明区域(Opaque Region)和被覆盖区域(Covered Region)。
假设一个应用程序窗口的宽度和高度分别为w和h,如图所示:
那么我们就可以将由(0,0)、(0, w)、(0, h)和(w,h)四个点组成的区域称为应用程序窗口的可见区域。
接下来,我们可以在一个应用程序窗口的可见区域挖一个洞出来,如下图所示:
这时候应用程序窗口真正的可见区域就需要减去中间被挖出来的洞。这个被挖出来的洞就称为应用程序窗口的透明可见区域。
如果应用程序窗口的可见区域的Alpha通道大于0并且小255,那么我们就认为应用程序窗口的可见区域是半透明的。有两种极端情况,即当应用程序窗口的可见区域的Alpha通道等于0或者255的时候。当等于0的时候,我们就认为应用程序窗口的可见区域是透明的,就如图5所示的洞一样,而当等于255的时候,我们就认为应用程序窗口的可见区域是完全不透明的。
上面我们讨论的应用程序窗口的可见区域是基于单个应用程序窗口而言的,当多个应用程序窗口叠加在一起的时候,在讨论一个应用程序窗口的可见区域的时候,就需要考虑位于它上面的其它应用程序窗口的可见区域的影响了。注意,一个应用程序窗口的可见区域只受位于它上面的其它应用程序窗口影响,而不会受到位于它下面的其它的应用程序窗口影响,因此,我们是按照从上到下的顺序(z-order)来计算系统中各个应用程序窗口的可见区域的。
为了方便描述,我们假设位于一个应用程序窗口上面的所有应用程序窗口组成了一个整体的可见区域(Above Covered Layers),并且这个可见区域与我们所要讨论的应用程序窗口相交,即它们叠加在一起,如图所示:
由蓝色矩形组成的区域即为上层所有应用程序窗口所组成的一个整体可见区域,这个整体可见区域与下面绿色矩形组成的一个应用程序窗口相交的部分,即由虚线所围成的区域,就是下面的一个应用程序窗口的被覆盖区域。
一个应用程序窗口的被覆盖区域有可能是半透明的,也有可能是完全不透明的,但是不可能是透明的,如图所示:
在原来由虚线围成的区域中,深蓝色的那部分区域就是完全不透明的(Above Opaque Layers),这时候由绿色矩形组成的应用程序窗口的可见区域除了要减去中间的洞(透明区域)之外,还要减去被覆盖的完全不透明区域,如下图所示:
从上面的讨论我们就可以清楚地知道,为了计算一个应用程序窗口的最终可见区域,我们需要知道:
- 应用程序窗口的左上角位置,以及宽度和高度,以便可以获得应用程序窗口的原始可见区域。
- 应用程序窗口的透明区域。
- 应用程序窗口的被覆盖完全不透明区域。
用第1步到的原始可见区域减去第2步的透明区域和第3步的被覆盖完全不透明区域,就可以得到一个应用程序窗口的最终可见区域。
为了获得第3步的被覆盖完全不透明区域,我们在计算一个应用程序窗口的最终可见区域的过程中,还需要将此前得到的应用程序窗口的完全不透明区域组合起来,形成一个覆盖完全不透明区域(Above Opaque Layers),因此,我们还需要知道:
- 应用程序窗口的完全不透明区域。
此外,由于一个应用程序窗口的被覆盖半透明区域是需要与上层的应用程序窗口可见区域执行混合计算的,因此,我们在计算系统中各个应用程序窗口的可见区域的过程中,还需要将所有上层的应用程序窗口可见区域组合起来形成一个覆盖区域(Above Covered Layers)。
所以计算所有Layer的可见区域逻辑, 按照Z-order逐个计算各layer的可见区域。对于Z-order值最大的layer,显然没有其它图层会遮盖它。所以它的可见区域(visibleRegion)应该是(当然,前提是这个layer没有超过屏幕区域)自身的大小再减去完全透明的部分(transparentRegion),由此计算出来的结果我们把它称为aboveCoveredLayers。这个变量应该是全局的,因为它需要被传递到后面的layers中,然后不断地累积运算,直到覆盖整个屏幕区域。
有了这些背景知识之后,接下来我们就可以分析SurfaceFlinger类的成员函数computeVisibleRegions的实现了。
computeVisibleRegions
computeVisibleRegions代码有点长,我们分段阅读:1
2
3
4
5
6
7
8
9
10
11void SurfaceFlinger::computeVisibleRegions(
const LayerVector& currentLayers, uint32_t layerStack,
Region& outDirtyRegion, Region& outOpaqueRegion)
{
ATRACE_CALL();
Region aboveOpaqueLayers;
Region aboveCoveredLayers;
Region dirty;
outDirtyRegion.clear();
这段代码定义了另外两个区域aboveOpaqueLayers,分别用来描述上层覆盖完全不透明区域(Above Opaque Layers)和上层覆盖区域(Above Covered Layers),上面讲过,这两个计算累加的结果。
我们接着往下阅读代码:1
2
3
4
5
6
7
8
9
10size_t i = currentLayers.size();
while (i--) {
const sp<Layer>& layer = currentLayers[i];
// 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 (s.layerStack != layerStack)
continue;
这段代码是一个while循环的前面几行。系统中所有需要计算可见区域的应用程序窗口都保存在参数currentLayers所描述的一个向量中。这段代码的while循环就是用来逐个地这些应用程序窗口的可见区域的。注意,这个while是先计算是按照从上到下的顺序来计算系统中各个应用程序窗口的可见区域的。
然后获得用来描述当前正在处理的应用程序窗口的当前渲染状态的一个State对象s,然后判断是否是当前应用程序的layerStack,否则就continue。
我们继续往下阅读代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28/*
* opaqueRegion: area of a surface that is fully opaque.
*/
Region opaqueRegion;
/*
* visibleRegion: area of a surface that is visible on screen
* and not fully transparent. This is essentially the layer's
* footprint minus the opaque regions above it.
* Areas covered by a translucent surface are considered visible.
*/
Region visibleRegion;
/*
* coveredRegion: area of a surface that is covered by all
* visible regions above it (which includes the translucent areas).
*/
Region coveredRegion;
/*
* transparentRegion: area of a surface that is hinted to be completely
* transparent. This is only used to tell when the layer has no visible
* non-transparent regions and can be removed from the layer list. It
* does not affect the visibleRegion of this layer or any layers
* beneath it. The hint may not be correct if apps don't respect the
* SurfaceView restrictions (which, sadly, some don't).
*/
Region transparentRegion;
接着再定义了四个Region对象opaqueRegion、visibleRegion、coveredRegion和transparentRegion,分别用来描述当前正在处理的应用程序窗口的完全不透明区域、可见区域、被覆盖区域和透明区域。这四个区域的含义和作用如前所述。
go on:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(layer->isVisible())) {
//是否是半透明
const bool translucent = !layer->isOpaque(s);
//layer的可见区域
Rect bounds(s.transform.transform(layer->computeBounds()));
//以便可以得到当前正在处理的应用程序窗口的初始可见区域visibleRegion
visibleRegion.set(bounds);
if (!visibleRegion.isEmpty()) {//计算透明区域
// Remove the transparent area from the visible region
if (translucent) {
//当前渲染状态的一个State对象s的成员变量transform指向的也是一个变换矩阵
//用来描述当前正在处理的应用程序窗口的位置、旋转方向和缩放因子等
const Transform tr(s.transform);
//函数接着判断当前正在处理的应用程序窗口是否被旋转过或者被缩放过
if (tr.transformed()) {
//判断当前正在处理的应用程序窗口是否被旋转和缩放得不规则
if (tr.preserveRects()) {
// transform the transparent region
transparentRegion = tr.transform(s.activeTransparentRegion);
} else {
//即当当前正在处理的应用程序窗口被旋转和缩放得不规则时,
//这时候对应用程序窗口的透明区域进行旋转或者缩放就会很复杂,
//于是函数就干脆将它的透明区域忽略掉
// transformation too complex, can't do the
// transparent region optimization.
transparentRegion.clear();
}
} else {//如果没有经过矩阵变换处理
transparentRegion = s.activeTransparentRegion;
}
}
// compute the opaque region
//当当前正在处理的应用程序窗口是完全不透明,并且旋转方向也是规则时,
//那么它的完全不透明区域opaqueRegion就等于前面计算所得到的可见区域visibleRegion
const int32_t layerOrientation = s.transform.getOrientation();
if (s.alpha==255 && !translucent &&
((layerOrientation & Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
}
}
}
这段代码用来计算当前正在处理的应用程序窗口的可见区域和完全不透明区域。只有在当前正在处理的应用程序窗口处于可见状态,并且它不是完全透明时,才需要计算这两个区域。我们看看Layer的isVisible函数,位于frameworks/native/services/surfaceflinger/Layer.cpp:1
2
3
4
5
6
bool Layer::isVisible() const {
const Layer::State& s(mDrawingState);
return !(s.flags & layer_state_t::eLayerHidden) && s.alpha
&& (mActiveBuffer != NULL || mSidebandStream != NULL);
}
当State对象s的成员变量flags的ISurfaceComposer::eLayerHidden位等于0时,就说明当前正在处理的应用程序窗口是处于可见状态的,而当它的另外一个成员变量alpha的值不等于0的时候,就说明当前正在处理的应用程序窗口不是完全透明的。
回到上面部分,接着计算透明区域。用来描述当前正在处理的应用程序窗口的当前渲染状态的一个State对象s的成员变量transform指向的也是一个变换矩阵,用来描述当前正在处理的应用程序窗口的位置、旋转方向和缩放因子等。
函数接着判断当前正在处理的应用程序窗口是否被旋转过或者被缩放过。如果是的话,那么前面调用变换矩阵tr的成员函数transformed的返回值就会等于true,即变量transformed的等于true。在这种情况下,函数就要相应地对当前正在处理的应用程序窗口的透明区域进行旋转或者缩放。但是有一种特殊情况,即当当前正在处理的应用程序窗口被旋转和缩放得不规则时,这时候对应用程序窗口的透明区域进行旋转或者缩放就会很复杂,于是函数就干脆将它的透明区域忽略掉。判断当前正在处理的应用程序窗口是否被旋转和缩放得不规则是通过调用变换矩阵tr的成员函数preserveRects来实现的,当它的返回值等于true的时候,就说明当前正在处理的应用程序窗口是否被旋转和缩放之后还是规则,否则就是不规则的。
当前正在处理的应用程序窗口的透明区域保存在State对象s的成员变量transparentRegion中,按照上述原理,函数按照以下规则来对它进行处理:
1)当变量transformed的等于false时,说明当前正在处理的应用程序窗口的透明区域就不需要进行旋转或者缩放,这时候就可以将这个透明区域保存在变量transparentRegionScreen中。
2)当变量transformed的等于true,并且变换矩阵tr的成员函数preserveRects的返回值也等于true时,那么就说明当前正在处理的应用程序窗口的透明区域需要进行旋转或者缩放,这时候通过调用变换矩阵tr的成员函数transform来实现的。 最终得到的透明区域同样是保存在变量transparentRegionScreen中。
3) 当变量transformed的等于true,并且变换矩阵tr的成员函数preserveRects的返回值等于false时,那么就说明需要忽略掉当前正在处理的应用程序窗口的透明区域,通过成员函数clear来实现的。
我们接着来看当前正在处理的应用程序窗口的完全不透明区域的计算过程。
当当前正在处理的应用程序窗口是完全不透明,并且旋转方向也是规则时,那么它的完全不透明区域opaqueRegion就等于前面计算所得到的可见区域visibleRegion。当当前正在处理的应用程序窗口的Alpha通道等于255,即当State对象s的成员变量alpha的值等于255,并且变量translucent的值等于false时,就说明它是完全不透明的,而当当前正在处理的应用程序窗口的旋转方向layerOrientation的Transform::ROT_INVALID位等于0的时候,就说明它的旋转方向是规则的。
go on:1
2
3
4
5
6
7
8// Clip the covered region to the visible region
coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
// Update aboveCoveredLayers for next (lower) layer
aboveCoveredLayers.orSelf(visibleRegion);
// subtract the opaque region covered by the layers above us
visibleRegion.subtractSelf(aboveOpaqueLayers);
这段代码用来计算当前正在处理的应用程序窗口的被覆盖区域,以及再进一步计算它的可见区域,主要考虑是否被上层的不透明区域覆盖了。
变量aboveCoveredLayers用来描述当前正在处理的应用程序窗口的所有上层应用程序窗口所组成的可见区域,将这个区域与当前正在处理的应用程序窗口的可见区域visibleRegion相交,就可以得到当前正在处理的应用程序窗口的被覆盖区域coveredRegion,而将这个区域与当前正在处理的应用程序窗口的可见区域visibleRegion相或一下,就可以得到下一个应用程序窗口的所有上层应用程序窗口所组成的可见区域aboveCoveredLayers。
变量aboveOpaqueLayers用来描述当前正在处理的应用程序窗口的所有上层应用程序窗口所组成的完全不透明区域,这个区域从当前正在处理的应用程序窗口的可见区域visibleRegion减去后,就可以得到当前正在处理的应用程序窗口的最终可见区域visibleRegion。
go on:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30// 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 {
/* compute the exposed region:
* the exposed region consists of two components:
* 1) what's VISIBLE now and was COVERED before
* 2) what's EXPOSED now less what was EXPOSED before
*
* note that (1) is conservative, we start with the whole
* visible region but only keep what used to be covered by
* something -- which mean it may have been exposed.
*
* (2) handles areas that were not covered by anything but got
* exposed because of a resize.
*/
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);
// accumulate to the screen dirty region
outDirtyRegion.orSelf(dirty);
这段代码用来计算屏幕的脏区域。我们首先解释一下屏幕的脏区域是如何计算的。将所有应用程序窗口的脏区域都组合起来,就可以得到屏幕的脏区域,这个脏区域就是需要重新执行渲染操作的。因此,为了得到屏幕的脏区域,我们要知道当前正在处理的应用程序窗口的脏区域,以及之前已经处理了的应用程序窗口脏区域组合。前者使用变量dirty来描述,而后者使用输出参数outDirtyRegion来描述。
我们首先来看当前正在处理的应用程序窗口的脏区域dirty是如何计算的。我们分两种情况来考虑。
1)首先考虑当前正在处理的应用程序窗口上一次的状态还未来得及处理的情况,即它当前的内容是脏的。在这种情况下,layer的成员变量contentDirty的值就会等于true。这时候我们就需要将该应用程序窗口的上一次可见区域,以及当前的可见区域合并起来,形成一个大的脏区域,这样就可以将两次渲染操作合并成一次来执行。当前正在处理的应用程序窗口的上一次可见区域保存在layer的成员变量visibleRegion中,而它前的可见区域保存在变量visibleRegion中。将这两者相或一下,就可以得到当前正在处理的应用程序窗口的脏区域dirty。
2)接着考虑当前正在处理的应用程序窗口上一次的状态已经处理了的情况,即它当前的内容不是脏的,这意味着它所要显示的内容没有发生变化。在这种情况下,就不需要重新渲染所有的可见区域。那么那些区域是需要重新渲染的呢?第一部分区域是之前是被覆盖的,现在不被覆盖了,第二部分是由于窗口大小变化而引发的新增不被覆盖区域。接下来,我们就来看看这两部分区域是如何计算的。
将一个应用程序窗口的当前可见区域减去被覆盖区域,就可以它的当前不被覆盖的区域newExposed,按照同样的方法,我们可以也可以得到它的上一次不被覆盖的区域oldExposed。注意,一个应用程序窗口的上一次可见区域和被覆盖区域分别保存与它相对应的一个Layer对象的成员变量visibleRegion和coveredRegion中。这样,将一个应用程序窗口的当前不被覆盖的区域newExposed减去它的上一次不被覆盖的区域oldExposed,就可以得到新增的不被覆盖区域,即可以得到第二部分需要重新渲染的区域。另一方面,将一个应用程序窗口的当前可见区域visibleRegion与它的上一次被覆盖区域oldCoveredRegion相交,就可以得到之前是被覆盖的而现在不被覆盖了的区域,即可以得到第一部分需要重新渲染的区域。将第一部分和第二部分需要重新渲染的区域组合起来,就可以得到当前正在处理的应用程序窗口的脏区域dirty。
得到了当前正在处理的应用程序窗口的脏区域dirty,接下来的事情就好办了。首先从该脏区域dirty减去上层的完全不透明区域,因为后者的渲染不需要当前应用程序窗口来参与,接着最将得到的新的脏区域dirty累加到输出参数outDirtyRegion中去,这样就可以得到目前为止,SurfaceFlinger服务需要渲染的脏区域。
go on:1
2
3
4
5
6
7
8
9
10
11
12 // Update aboveOpaqueLayers for next (lower) layer
aboveOpaqueLayers.orSelf(opaqueRegion);
// Store the visible region in screen space
layer->setVisibleRegion(visibleRegion);
layer->setCoveredRegion(coveredRegion);
layer->setVisibleNonTransparentRegion(
visibleRegion.subtract(transparentRegion));
}
outOpaqueRegion = aboveOpaqueLayers;
}
这段代码是前面的while循环的几行结束代码,主要用来做三件事情。
第一件事情是计算到目前为止所得到的上层应用程序窗口的完全不透明区域,这是通过组合当前正在处理的应用程序窗口的完全不透明区域与位于它上面的的所有应用程序窗口的完全不透明区域aboveOpaqueLayers来得到的,并且最终结果保存在变量aboveOpaqueLayers中。
第二件事情是调用layer的成员函数setVisibleRegion、setCoveredRegion和setVisibleNonTransparentRegion来保存当前正在处理的应用程序窗口的可见区域、被覆盖区域和没有透明区域的可见区域。
第三件事情是,函数还将前面所有的应用程序窗口组成的完全不透明区域aboveOpaqueLayers保存在输出参数opaqueRegion,以便可以返回给调用者使用。
这就是计算Layer可视区域的所有流程,只要理解了里面每个变量代表对应含义区域的意义,就不难分析。这里我们rebuildLayerStacks流程就分析完了。我们继续往下走,分析下一步。
setUpHWComposer
合成步骤的下一步就是setUpHWComposer函数调用,配置硬件合成器。
回顾HWC
我们之前在Android SurfaceFlinger 学习之路(二)—-SurfaceFlinger概述讲过,用于合成surface的功能模块可以有2个,OpenGL ES & HWC,它的管理实在HWC里面实现的。
官网也给出了一些解释,https://source.android.google.cn/devices/graphics/arch-sf-hwc ,不过中文翻译的不是很好,最好看看英文:
Hardware Composer HAL (HWC) 是在 Android 3.0 中推出的,并且多年来一直都在不断演进。它主要是用来确定通过可用硬件来合成缓冲区的最有效方法。作为 HAL,其实现是特定于设备的,而且通常由显示设备硬件原始设备制造商 (OEM) 完成。
当考虑叠加平面时,很容易发现这种方法的好处。它的目的是在显示硬件(而不是 GPU)中将多个缓冲区合成在一起。例如,假设有一部处于纵向模式的普通 Android 手机,其状态栏在顶部,导航栏在底部,其他地方为应用内容。每个层的内容都在单独的缓冲区中。您可以使用以下任一方法处理合成:
- 将应用内容渲染到暂存缓冲区中,然后在其上渲染状态栏,再在其上渲染导航栏,最后将暂存缓冲区传送到显示硬件。
- 将三个缓冲区全部传送到显示硬件,并告知它从不同的缓冲区读取屏幕不同部分的数据。
后一种方法可以显著提高效率。
上面两种合成分别叫离线合成和在线合成。
离线合成:先将所有图层画到一个最终层(FrameBuffer)上,再将FrameBuffer送到LCD显示。由于合成FrameBuffer与送LCD显示一般是异步的(线下生成FrameBuffer,需要时线上的LCD去取),因此叫离线合成。
在线合成:不使用FrameBuffer,在LCD需要显示某一行的像素时,用显示控制器将所有图层与该行相关的数据取出,合成一行像素送过去。只有一个图层时,又叫Overlay技术。
由于省去合成FrameBuffer时读图层,写FrameBuffer的步骤,大幅降低了内存传输量,减少了功耗,但这个需要硬件支持。
效率对比:大部分情况下,在线合成比起离线合成有很明显的优势,大幅降低了内存带宽的消耗。不过对于多屏显示,静态场景(仅限LCD不带缓存的情况),离线合成会有优势,做下简单的计算不难推得。
显示处理器功能差异很大。overlay的数量(无论层是否可以旋转或混合)以及对定位和叠加的限制很难通过 API 表达。HWC 会尝试通过一系列决策来适应这种多样性:
- SurfaceFlinger给HWC提供layer list,询问如何处理这些layer;
- HWC将每个layer标记为overlay或者GLES composition,然后回馈给SurfaceFlinger;
- SurfaceFlinger需要去处理那些GLES的合成,而不用去管overlay的合成,最后将overlay的layer和GLES合成后的buffer发送给HWC处理。
用之前一幅图表示:
屏幕上的内容没有变化时,overlay的效率可能会低于 GL 合成。当overlay内容具有透明像素且overlay混合在一起时,尤其如此。在此类情况下,HWC 可以选择为部分或全部层请求 GLES 合成,并保留合成的缓冲区。如果 SurfaceFlinger 返回要求合成同一组缓冲区,HWC 可以继续显示先前合成的暂存缓冲区。这可以延长闲置设备的电池续航时间。
运行 Android 4.4 或更高版本的设备通常支持 4 个overlay。尝试合成多于overlay的层会导致系统对其中一些层使用 GLES 合成,这意味着应用使用的层数会对功耗和性能产生重大影响。
关于HWC HAL有更详细的解释,官网在置如此:https://source.android.google.cn/devices/graphics/implement-hwc ,中文翻译的依旧有些别扭:
Hardware Composer HAL (HWC) 由 SurfaceFlinger 用来将 Surface 合成到屏幕。HWC 可以抽象出叠加层和 2D 位块传送器等对象,有助于分载通常使用 OpenGL 完成的一些工作。
Android 7.0 包含新版本的 HWC (HWC2),由 SurfaceFlinger 用来与专门的窗口合成硬件进行通信。SurfaceFlinger 包含使用 3D 图形处理器 (GPU) 执行窗口合成任务的备用路径,但由于以下几个原因,此路径并不理想:
- 通常,GPU 未针对此用例进行过优化,因此能耗可能要大于执行合成所需的能耗。
- 每次 SurfaceFlinger 使用 GPU 进行合成时,应用都无法使用处理器进行自我渲染,因此应尽可能使用专门的硬件而不是 GPU 进行合成。
由于 Hardware Composer 抽象层后的物理显示设备硬件可因设备而异,因此很难就具体功能提供建议。一般来说,请遵循以下准则:
- HWC 应至少支持 4 个叠加层(状态栏、系统栏、应用和壁纸/背景)。
- 层可以大于屏幕,因此 HWC 应能处理大于显示屏的层(例如壁纸)。
- 应同时支持预乘每像素 Alpha 混合和每平面 Alpha 混合。
- HWC 应能消耗 GPU、相机和视频解码器生成的相同缓冲区,因此支持以下某些属性很有帮助:
- RGBA 打包顺序
- YUV 格式
- 平铺、重排和步幅属性
- 为了支持受保护的内容,必须提供受保护视频播放的硬件路径。
常规建议是首先实现非运行的 HWC;在结构完成后,实现一个简单的算法,以将合成委托给 HWC(例如,仅将前 3 个或前 4 个 Surface 委托给 HWC 的叠加硬件)。
专注于优化,例如智能地选择要发送到叠加硬件的 Surface,以最大限度提高从 GPU 移除的负载。另一种优化是检测屏幕是否正在更新;如果不是,则将合成委托给 OpenGL 而不是 HWC,以节省电量。当屏幕再次更新时,继续将合成分载到 HWC。
为常见用例做准备,如:
- 纵向和横向模式下的全屏游戏
- 带有字幕和播放控件的全屏视频
- 主屏幕(合成状态栏、系统栏、应用窗口和动态壁纸)
- 受保护的视频播放
- 多显示设备支持
这些用例应针对常规可预测的用途,而不是很少遇到的边缘用例(否则,优化将收效甚微)。实现必须平衡动画流畅性和交互延迟时间这两个相互矛盾的目标。
根据这些Google定义的这些准则,我们能够更好地分析配置硬件合成器的步骤。
准备工作
在分析setUpHWComposer函数之前,我们要回顾一下Android SurfaceFlinger 学习之路(五)—-VSync 工作原理中的硬件加载
的部分,初始化显示设备和HWComposer设备的内容。
从上一部分得知,比如使用3D合成,需要大面积的像素混合计算和大量的内存传输(GPU读写GraphicBuffer所需),对GPU和DDR来说是一个巨大的负担。在GPU/DDR重度使用的场景(比如玩游戏),会造成发热、卡顿等。
为了提升性能,减少功耗,可以将合成这个过程交由另一个芯片完成,减轻GPU负担。进一步,直接让这个芯片连LCD,在LCD需要显示某一行时在线合成。
HwComposer便是这一个/多个专用合成芯片的驱动HAL层。
驱动由集成芯片系统的厂商自行设计,但需要遵循一定的标准,这个标准就是Android规定的HwComposer接口。
hwcomposer的接口定义位于此文件:
hardware/libhardware/include/hardware/hwcomposer.h
其中部分宏定义在:
hardware/libhardware/include/hardware/hwcomposer_defs.h
相关结构解释如下:
Layer
在SurfaceFlinger中,Layer对应于window表示一个Buffer循环体系,对HwComposer而言,Layer仅指代当前Buffer,也即SurfaceFlinger中的Layer的当前帧。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87typedef struct hwc_layer_1 {
int32_t compositionType;//合成类型,SurfaceFlinger将合成目标Framebuffer的合成类型设为HWC_FRAMEBUFFER_TARGET,其他hwcomposer在prepare时根据实际情况修改
//在(*prepare)()调用前,需要复位HWC_BACKGROUND or HWC_FRAMEBUFFER,需要设置HWC_GEOMETRY_CHANGED的标志符,并在(*prepare)()过程中保持,
/*
* HWC_BACKGROUND:(*prepare)()调用前设置,表明这是个特殊的"background"的层,backgroundColor是无效的,HWC向HWC_FRAMEBUFFER切换此值,并表示无法使用backgroundColor。
* HWC_FRAMEBUFFER_TARGET:在prepare前设置此值,此值表明此层是framebuffersurface层,作为OpenGLEScomposition的对象,如果HWC设置其他层为HWC_OVERLAY或则为HWC_BACKGROUND,则在set()过程中opengles则什么都不干。
* 此标志仅仅用在版本至少为HWC_DEVICE_API_VERSION_1_1,在老版本的过程中,OpenGLES target 与(dpy, sur)通信,在HWC实现的过程中此值不能设置。
* 该Layer是3D合成的目标Layer
* HWC_FRAMEBUFFER:在(*prepare)()调用前设置,仅仅在HWC_GEOMETRY_CHANGED flag 也在设置的时候设置,并表明此层将使用opengles画进framebuffer中。HWC可以切换此值到HWC_OVERLAY表明其将要管理此层。
* hwcomposer无法处理此Layer,该Layer需要走3D合成流程,用OpenGL绘制
* HWC_OVERLAY:在(*prepare)()过程中,通过HWC设置,表明此层由HWC设置,不能通过OpenGLES 合成。
* 该Layer为硬件合成器所处理,不需要OpenGLES去渲染
* HWC_SIDEBAND:在(*prepare)()前设置,此值表明此层的内容来自于边带视频流,此流在适当的时间(去同步多媒体流),与其他层当前内容进行合成,显示结果图片。此现象依赖于正常的prepare/set周期。prepare/set调用仅仅发生在其他层的改变,或则是边带视频流的位置或则大小的改变。
假如h/w composer 无法管理层由于边带视频流的原因(unsupportedscaling/blending/rotation, or too many sideband layers),其可以在(*prepare)()设置合成类型为HWC_FRAMEBUFFER。但是,这样做显示维实体颜色,因为平台无法使用GPU进行合成边带视频层。这个问题在未来的平台版本中将得到改善。
* 该Layer为视频的边频带,需要硬件合成器作特殊处理,若不支持,OpenGL方式只能以一个色块替代,这个标志是外界(应用/驱动)调用窗口系统的perform方法配置的
* HWC_CURSOR_OVERLAY:在(*prepare)()期间,设置HWC实现,这个值意味着此层的合成将要被HWC的管理,另外,客户端在屏幕上可以异步刷新,这个层的位置可以使用setCursorPositionAsync() api。
* 该Layer可通过setCursorPositionAsync 方法改变坐标
*/
uint32_t hints;//hwcomposer设置,通知SurfaceFlinger需要修改的配置
/*
HWC_HINT_TRIPLE_BUFFER = 0x00000001:表示需要SurfaceFlinger将此Layer改成3Buffer循环
HWC_HINT_CLEAR_FB = 0x00000002:要求SurfaceFlinger清空该Layer位置的FrameBuffer数据(即置0)
*/
uint32_t flags;//SurfaceFlinger设置,hwcomposer作处理
/*
HWC_SKIP_LAYER = 0x00000001:此Layer不参与合成,应当忽略
HWC_IS_CURSOR_LAYER = 0x00000002:此Layer建议设定为一个CURSOR_LAYER,hwcomposer能处理的话将其合成类型改为HWC_CURSOR_OVERLAY
*/
/*该Layer的颜色/Buffer信息*/
union {
hwc_color_t backgroundColor;//背景颜色,适用于纯色Layer,hwc_color_t 为一个 argb 结构体
struct {
union {
buffer_handle_t handle;//此即之间提到的GraphicBuffer
const native_handle_t* sidebandStream;//HWC_SIDEBAND类型Layer的buffer
};
uint32_t transform;//该Layer所需要作的变换,具体为:
/*
HWC_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H//水平翻转
HWC_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V//垂直翻转
HWC_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,//需要旋转90度
HWC_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,//需要旋转180度
HWC_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,//需要旋转270度
*/
int32_t blending;//当前Layer绘制时,和底色/目标色的混合方式
//HWC_BLENDING_NONE = 0x100:不混合,直接覆盖
//HWC_BLENDING_PREMULT = 0x105:该Layer的颜色已经做过alpha预乘,因此混合方式为 src + (1-src.a)*dst
//HWC_BLENDING_COVERAGE = 0x405:该Layer的颜色未做过预乘,按 src.a * src + (1-src.a) * dst 的方式混合
union {
// crop rectangle in integer (pre HWC_DEVICE_API_VERSION_1_3)
hwc_rect_t sourceCropi;
hwc_rect_t sourceCrop; // just for source compatibility
// crop rectangle in floats (as of HWC_DEVICE_API_VERSION_1_3)
hwc_frect_t sourceCropf;
};//该Layer取哪一个区域进行合成
hwc_rect_t displayFrame;//该Layer合成的目标区域
hwc_region_t visibleRegionScreen;//该Layer的可见区域,该区域必然是displayFrame的子集。这个区域由SurfaceFlinger计算而得,用于提示hwcomposer不去合成该Layer的不可见区域,hwcomposer中应当以这个为基准,对应计算该Layer相应的sourcecrop。
int acquireFenceFd;//由Buffer生产者创建,SurfaceFlinger传递进来,hwcomposer在使用该Layer的Buffer之前,需要等这个fence
int releaseFenceFd;//由hwcomposer创建,生产者在使用该Buffer之前需要等此fence
uint8_t planeAlpha;//整个Layer的alpha值,在取Layer的像素作运算之前,需要先乘 planeAlpha/255。
/* Pad to 32 bits */
uint8_t _pad[3];//用于结构体对齐,占位用
hwc_region_t surfaceDamage;//记录相对上一次合成而言,发生了改变的source区域
};
};
//保留位,用于驱动层自行设计
uint8_t reserved[120 - 112];
uint8_t reserved[96 - 84];
} hwc_layer_1_t;
这里面最难理解和最易出错的是 SourceCrop、DisplayFrame和VisibleRegion,在处理SOC上的显示问题时,这往往是首先考虑的因素:
如图所示,该Layer的显示区域部分被L2完全挡住,source crop 为该Layer参与合成的范围,display frame 为该Layer合成的目标区域,visibleRegion为该Layer被挡住后,剩余的可见区域集。
这里我用了我的渣渣小米5,在Home页面,然后进入调试模式,输入adb shell dumpsys SurfaceFlinger :
截取出这段信息,这段信息是SurfaceFlinger告知硬件合成器如何进行合成的。最后一个FramebufferTarget是目标层,不算进去,参与合成的图层是三个,分别是 :
- com.android.systemui.ImageWallpaper
- com.miui.home/com.miui.home.launcher.Launcher
- StatusBar
其他参数对比我们上面的hwc_layer_1_t结构体,就能理解这些参数的意义。
Display
1 | typedef struct hwc_display_contents_1 { |
物理显示屏表示连接实际的显示仪器如LCD,目的是产生显示效果,可以使用在线合成。
虚拟显示屏表示目的是合成一个Buffer,不需要理会这个Buffer后续如何产生显示效果,这时需要把所有图层合成到指定的Buffer上。这种情况下必须离线合成。典型场景是手机连WFD/hdmi,手机合成好的Buffer通过wifi/hdmi传输到电视上显示。
Device
最后是device的函数指针定义
1 | typedef struct hwc_composer_device_1 { |
实现
然后我们看看setUpHWComposer的实现。这个函数有点长,但是每个步骤都比较清晰,我们分步骤查看:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35void SurfaceFlinger::setUpHWComposer() {
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
// If nothing has changed (!dirty), don't recompose.
// If something changed, but we don't currently have any visible layers,
// and didn't when we last did a composition, then skip it this time.
// The second rule does two things:
// - When all layers are removed from a display, we'll emit one black
// frame, then nothing more until we get new layers.
// - When a display is created with a private layer stack, we won't
// emit any black frames until a layer is added to the layer stack.
//如果没有改变(!dirty),不重新合成
//如果有变化,但是当前没有可见的layers,并且上次合成过,那么这次跳过
//有两个规则如下:
//1.当所有的layers从显示屏移除,我们发射一个黑的frame,在来到新的layer之前都是黑的
//2.当一个显示屏被创建时候带着一个私有的layer栈,我们直到新的layer被添加到这个layer stack时,
//才发射黑的frame
bool mustRecompose = dirty && !(empty && wasEmpty);
ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
"dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
mustRecompose ? "doing" : "skipping",
dirty ? "+" : "-",
empty ? "+" : "-",
wasEmpty ? "+" : "-");
//DisplayDevice的beginFrame函数,调用FrameBufferSurface的beginFrame函数,返回NO_ERROR
mDisplays[dpy]->beginFrame(mustRecompose);
if (mustRecompose) {
mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
}
}
这一步检查每个显示的dirty区域是否改变了,如果是就要Recompose。DisplayDevice的beginFrame函数,调用FrameBufferSurface的beginFrame函数,返回NO_ERROR。如果需要重新合成,将DisplayDevice的lastCompositionHadVisibleLayers标志只为true(!empty)。
这一步作用不大,可以忽略。
go on:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29HWComposer& hwc(getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
// build the h/w work list
if (CC_UNLIKELY(mHwWorkListDirty)) {
mHwWorkListDirty = false;
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {//遍历mDisplays
sp<const DisplayDevice> hw(mDisplays[dpy]);
//以前我们讲过,这个id就是不同display的type,比如0,1,2
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
const Vector< sp<Layer> >& currentLayers(//遍历DisplayDevice所有可见layer
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
if (hwc.createWorkList(id, count) == NO_ERROR) {//根据layer数量调用createWorkList创建hwc_layer_list_t列表
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
const sp<Layer>& layer(currentLayers[i]);
//设置HWC每一个帧hwc_layer_1_t的Geometry信息
//如transform/orientation/alpha等
layer->setGeometry(hw, *cur);
if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
cur->setSkip(true);
}
}
}
}
}
}
这一步主要工作有:
1)遍历mDisplays,在所有显示屏信息中,遍历DisplayDevice所有可见layer;
2)根据layer数量调用createWorkList创建hwc_layer_list_t列表;
3)设置HWC每一个帧hwc_layer_1_t的Geometry信息,如transform/orientation/alpha等。
我们先来看下HWComposer的createWorkList函数实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
return BAD_INDEX;
}
if (mHwc) {
DisplayData& disp(mDisplayData[id]);
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// we need space for the HWC_FRAMEBUFFER_TARGET
//当支持Open GL合成时候,会把numLayer数目+1,
//这个多余的1就是合成目标HWC_FRAMEBUFFER_TARGET
//之前从dumpsys SurfaceFlinger中能看到最后一个是HWC_FRAMEBUFFER_TARGET
numLayers++;
}
////当DisplayData中的list为空,我们就要malloc
if (disp.capacity < numLayers || disp.list == NULL) {
//整个申请内存长度,hwc_display_contents_1_t结构体本身的长度加上后面hwc_layer_1_t个数的长度
size_t size = sizeof(hwc_display_contents_1_t)
+ numLayers * sizeof(hwc_layer_1_t);
free(disp.list);
disp.list = (hwc_display_contents_1_t*)malloc(size);
disp.capacity = numLayers;
}
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1];
//DisplayData的framebufferTarget清0
memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t));
const DisplayConfig& currentConfig =
disp.configs[disp.currentConfig];
const hwc_rect_t r = { 0, 0,
(int) currentConfig.width, (int) currentConfig.height };
disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
disp.framebufferTarget->hints = 0;
disp.framebufferTarget->flags = 0;
disp.framebufferTarget->handle = disp.fbTargetHandle;
disp.framebufferTarget->transform = 0;
disp.framebufferTarget->blending = HWC_BLENDING_PREMULT;
//framebufferTarget的sourceCrop初始化
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
disp.framebufferTarget->sourceCropf.left = 0;
disp.framebufferTarget->sourceCropf.top = 0;
disp.framebufferTarget->sourceCropf.right =
currentConfig.width;
disp.framebufferTarget->sourceCropf.bottom =
currentConfig.height;
} else {
disp.framebufferTarget->sourceCrop = r;
}
//framebufferTarget的displayFrame初始化
disp.framebufferTarget->displayFrame = r;
disp.framebufferTarget->visibleRegionScreen.numRects = 1;
disp.framebufferTarget->visibleRegionScreen.rects =
&disp.framebufferTarget->displayFrame;
disp.framebufferTarget->acquireFenceFd = -1;
disp.framebufferTarget->releaseFenceFd = -1;
disp.framebufferTarget->planeAlpha = 0xFF;
}
disp.list->retireFenceFd = -1;
disp.list->flags = HWC_GEOMETRY_CHANGED;
disp.list->numHwLayers = numLayers;
}
return NO_ERROR;
}
当支持Open GL合成时候,会把numLayer数目+1,这个多余的1就是合成目标HWC_FRAMEBUFFER_TARGET,之前从dumpsys SurfaceFlinger中能看到最后一个是HWC_FRAMEBUFFER_TARGET。
然后就是为DisplayData的list申请内存,这个内存要先hwc_display_contents_1_t结构体本身的长度加上后面hwc_layer_1_t个数的长度。
后面用DisplayData中list中hwLayers最后一个作为DisplayData中的framebufferTarget。
最后就是framebufferTarget的一些初始化操作。
关于DisplayData结构体,可以回顾Android SurfaceFlinger 学习之路(五)—-VSync 工作原理中的硬件加载
的部分,初始化显示设备和HWComposer设备的内容,这里先贴出来结构体内容:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24struct DisplayData {
DisplayData();
~DisplayData();
Vector<DisplayConfig> configs;
size_t currentConfig;
uint32_t format; // pixel format from FB hal, for pre-hwc-1.1
bool connected;
bool hasFbComp;
bool hasOvComp;
size_t capacity;
//上面构造Worklist,并且给DisplayData:list 申请空间
hwc_display_contents_1* list;
//DisplayData中list中hwLayers最后一个作为DisplayData中的framebufferTarget
hwc_layer_1* framebufferTarget;
buffer_handle_t fbTargetHandle;
sp<Fence> lastRetireFence; // signals when the last set op retires
sp<Fence> lastDisplayFence; // signals when the last set op takes
// effect on screen
buffer_handle_t outbufHandle;
sp<Fence> outbufAcquireFence;
// protected by mEventControlLock
int32_t events;
};
DisplayData 结构体的成员list是一个hwc_display_contents_1指针,这个hwc_display_contents_1结构体我们上面讲过。里面有个联合体union,联合体里面又有两个结构体。
- 第一个结构体是HWC_DEVICE_VERSION_1_0 使用,dpy和sur对应于EGLDisplay 和 EGLSurface,这是EGL使用的
- 第二个结构体是HWC_DEVICE_VERSION_1_3 之后支持 hwcomposer合成多屏,这里是指虚拟屏的输出buffer和对应的fence
hwc_display_contents_1后面成员保存了后面还保存了layer的个数和hwc_layer_1_t 数组的起始地址hwLayers[0]。
DisplayData 结构体的成员framebufferTarget是一个hwc_layer_1指针,这个hwc_layer_1我们上面也贴出来了。相关成员可以参考上面的内容,包括上面提到的 SourceCrop、DisplayFrame和VisibleRegion。其主要数据在buffer_handle_t handle中,buffer_handle_t 其实就是native_handle_t之前分析过,里面有共享内存的fd和地址。关于buffer_handle_t可以回顾之前申请GraphicBuffer的内容。
然后就是设置HWC每一个帧hwc_layer_1_t的Geometry信息,如transform/orientation/alpha等。不过这之前我们要先看看HWComposer的begin和end函数,还有相关类或者结构体。
先看下HWComposer中的begin函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15HWComposer::LayerListIterator HWComposer::begin(int32_t id) {
return getLayerIterator(id, 0);
}
HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {//pass
return LayerListIterator();
}
const DisplayData& disp(mDisplayData[id]);
if (!mHwc || !disp.list || index > disp.list->numHwLayers) {//pass
return LayerListIterator();
}
//go to
return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers), index);
}
这里不走前两个if,最后新建一个LayerListIterator对象,构造函数中传入HWCLayerVersion1对象,和index,为0。我们贴出来LayerListIterator类结构:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
* Iterator through a HWCLayer list.
* This behaves more or less like a forward iterator.
*/
class LayerListIterator {
friend struct HWComposer;
HWCLayer* const mLayerList;
size_t mIndex;
LayerListIterator() : mLayerList(NULL), mIndex(0) { }
LayerListIterator(HWCLayer* layer, size_t index)
: mLayerList(layer), mIndex(index) { }
// we don't allow assignment, because we don't need it for now
LayerListIterator& operator = (const LayerListIterator& rhs);
public:
// copy operators
LayerListIterator(const LayerListIterator& rhs)
: mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) {
}
~LayerListIterator() { delete mLayerList; }
// pre-increment
LayerListIterator& operator++() {
mLayerList->setLayer(++mIndex);
return *this;
}
// dereference
HWCLayerInterface& operator * () { return *mLayerList; }
HWCLayerInterface* operator -> () { return mLayerList; }
// comparison
bool operator == (const LayerListIterator& rhs) const {
return mIndex == rhs.mIndex;
}
bool operator != (const LayerListIterator& rhs) const {
return !operator==(rhs);
}
};
这里要留意一下后面几个运算符重载,后面会用到。
这里面HWCLayerVersion1就是mLayerList, index就是mIndex。HWCLayerVersion1的结构如下:1
2
3
4
5
6
7
8
9
10
11/*
* Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0.
* This implements the HWCLayer side of HWCIterableLayer.
*/
class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> {
struct hwc_composer_device_1* mHwc;
public:
HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer)
: Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc) { }
//ignore
构造函数中传入了mHwc和disp.list->hwLayers,就是HWC Device HAL层指针和上面我们分析的合成该显示屏的所有Layer。
而我们再来看看下HWComposer中的end函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18HWComposer::LayerListIterator HWComposer::end(int32_t id) {
size_t numLayers = 0;
if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) {
const DisplayData& disp(mDisplayData[id]);
if (mHwc && disp.list) {
numLayers = disp.list->numHwLayers;//获取到list中laye的个数
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET,
// which we ignore when iterating through the layer list.
ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id);
if (numLayers) {
numLayers--;//变成最后一个用于合成的layer,因为本来最后一个是HWC_FRAMEBUFFER_TARGET
}
}
}
}
return getLayerIterator(id, numLayers);//和上面一样,只是传入的index不一样。
}
end函数和begin很像只是在调用getLayerIterator的时候,begin传入0,end传入layer的最后一位,变成最后一个用于合成的layer,因为本来最后一个是HWC_FRAMEBUFFER_TARGET。最后就是mIndex成员变量不一样。
接着我们回到上面setUpHWComposer函数,第二部第三个步骤,layer->setGeometry(hw, (星号,解引用,MD语法转义了这个符号)cur);这里layer是Layer对象,hw是DisplayDevice对象,cur是HWComposer::LayerListIterator对象。我们上面强调了一定要注意LayerListIterator类内部的运算符重载,这里用到了(星号,解引用,MD语法转义了这个符号)运算符:1
HWCLayerInterface& operator * () { return *mLayerList; }
而上面的mLayerList就是HWCLayerVersion1对象。所以我们继续查看Layer的setGeometry函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75void Layer::setGeometry(
const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer)
{
layer.setDefaultState();
// enable this layer
layer.setSkip(false);
//受安全保护的layer,不可以在进程间传入,所以合成时候跳过
if (isSecure() && !hw->isSecure()) {
layer.setSkip(true);
}
// this gives us only the "orientation" component of the transform
const State& s(getDrawingState());
//半透明颜色处理
if (!isOpaque(s) || s.alpha != 0xFF) {
layer.setBlending(mPremultipliedAlpha ?
HWC_BLENDING_PREMULT :
HWC_BLENDING_COVERAGE);
}
// apply the layer's transform, followed by the display's global transform
// here we're guaranteed that the layer's transform preserves rects
//处理displayFrame,sourceCrop,还有透明度
Rect frame(s.transform.transform(computeBounds()));
frame.intersect(hw->getViewport(), &frame);
const Transform& tr(hw->getTransform());
layer.setFrame(tr.transform(frame));
layer.setCrop(computeCrop(hw));
layer.setPlaneAlpha(s.alpha);
/*
* Transformations are applied in this order:
* 1) buffer orientation/flip/mirror
* 2) state transformation (window manager)
* 3) layer orientation (screen orientation)
* (NOTE: the matrices are multiplied in reverse order)
*/
const Transform bufferOrientation(mCurrentTransform);
Transform transform(tr * s.transform * bufferOrientation);
//如果这个图形缓冲区之前曾经被旋转过,例如,被水平翻转或者垂直翻转过,那么在对它进行合并之前,还需要将它的旋转方向恢复回来。
if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
/*
* the code below applies the display's inverse transform to the buffer
*/
uint32_t invTransform = hw->getOrientationTransform();
uint32_t t_orientation = transform.getOrientation();
// calculate the inverse transform
if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
NATIVE_WINDOW_TRANSFORM_FLIP_H;
// If the transform has been rotated the axis of flip has been swapped
// so we need to swap which flip operations we are performing
bool is_h_flipped = (t_orientation & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
bool is_v_flipped = (t_orientation & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
if (is_h_flipped != is_v_flipped) {
t_orientation ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
}
// and apply to the current transform
transform = Transform(t_orientation) * Transform(invTransform);
}
// this gives us only the "orientation" component of the transform
const uint32_t orientation = transform.getOrientation();
if (orientation & Transform::ROT_INVALID) {
// we can only handle simple transformation
layer.setSkip(true);
} else {
layer.setTransform(orientation);
}
}
上面就是设置Layer的Geometry信息:
1)受安全保护的layer,不可以在进程间传入,所以合成时候跳过。界面受到安全保护的应用程序窗口的内容是不可以在进程间传输的,这个属性主要是应用在屏幕截图中。例如,如果系统中存在一个界面受到安全保护的应用程序窗口,那么我们就不可以请求SurfaceFlinger服务执行截屏功能,因为SurfaceFlinger服务截取下来的屏幕会被传输给请求的进程使用。
2)处理displayFrame,sourceCrop,还有透明度。
3)如果这个图形缓冲区之前曾经被旋转过,例如,被水平翻转或者垂直翻转过,那么在对它进行合并之前,还需要将它的旋转方向恢复回来。
这样我们setUpHWComposer第二部就完了,go on:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// set the per-frame data
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
/*
* update the per-frame h/w composer data for each layer
* and build the transparent region of the FB
*/
//将layer的mActiveBuffer设置到HWComposer中去
const sp<Layer>& layer(currentLayers[i]);
layer->setPerFrameData(hw, *cur);
}
}
}
有了上面的基础,我们先留意上面强调过,注意LayerListIterator类内部的运算符重载,这里需要用到的是++的重载:1
2
3
4
5
6
7
8LayerListIterator& operator++() {
mLayerList->setLayer(++mIndex);
return *this;
}
virtual status_t setLayer(size_t index) {
mCurrentLayer = &mLayerList[index];
return NO_ERROR;
}
会调用mLayerList->setLayer函数,setLayer会从mLayerList中设置当前的mCurrentLayer,通过mLayerList, 这个变量就是disp.list->hwLayers。
这样准备工作就好了,我们再来分析Layer的setPerFrameData函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer) {
// we have to set the visible region on every frame because
// we currently free it during onLayerDisplayed(), which is called
// after HWComposer::commit() -- every frame.
// Apply this display's projection's viewport to the visible region
// before giving it to the HWC HAL.
const Transform& tr = hw->getTransform();
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
layer.setVisibleRegionScreen(visible);
if (mSidebandStream.get()) {
layer.setSidebandStream(mSidebandStream);
} else {
// NOTE: buffer can be NULL if the client never drew into this
// layer yet, or if we ran out of memory
layer.setBuffer(mActiveBuffer);
}
}
主要就是调用了HWCLayerVersion1的setBuffer函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
if (buffer == 0 || buffer->handle == 0) {
getLayer()->compositionType = HWC_FRAMEBUFFER;
getLayer()->flags |= HWC_SKIP_LAYER;
getLayer()->handle = 0;
} else {
if (getLayer()->compositionType == HWC_SIDEBAND) {
// If this was a sideband layer but the stream was removed, reset
// it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare.
getLayer()->compositionType = HWC_FRAMEBUFFER;
}
getLayer()->handle = buffer->handle;
}
}
//
inline HWCTYPE* getLayer() { return mCurrentLayer; }
用getLayer函数设置其handle,而getLayer就是mCurrentLayer。之前mCurrentLayer会一个个遍历各个Layer,这样就把所有的layer都设置其handle,就是hwc_layer_1_t中的handle。这样就把GraphicBuffer和hwc_layer_1_t关联起来了。
go on:ignore // If possible, attempt to use the cursor overlay on each display.
go on:1
2
3
4
5
6
7
8
9
10
11 //将使用哪种合成报告给HWC
status_t err = hwc.prepare();
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
//return NO_ERROR
hw->prepareFrame(hwc);
}
}
}
最后会调用HWComposer的prepare函数,将使用哪种合成报告给HWC,我们再来看下这个函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81status_t HWComposer::prepare() {
for (size_t i=0 ; i<mNumDisplays ; i++) {
DisplayData& disp(mDisplayData[i]);
if (disp.framebufferTarget) {//这里其实就是disp.list中最后一个layer
// make sure to reset the type to HWC_FRAMEBUFFER_TARGET
// DO NOT reset the handle field to NULL, because it's possible
// that we have nothing to redraw (eg: eglSwapBuffers() not called)
// in which case, we should continue to use the same buffer.
LOG_FATAL_IF(disp.list == NULL);
disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
}
if (!disp.connected && disp.list != NULL) {
ALOGW("WARNING: disp %zu: connected, non-null list, layers=%zu",
i, disp.list->numHwLayers);
}
mLists[i] = disp.list;//DisplayData的list就是mList的一个组员,hwc_display_contents_1*
if (mLists[i]) {
//HWC_DEVICE_VERSION_1_3 之后支持 hwcomposer合成多屏,这里是指虚拟屏的输出buffer和对应的fence
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
mLists[i]->outbuf = disp.outbufHandle;
mLists[i]->outbufAcquireFenceFd = -1;
} else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {// HWC_DEVICE_VERSION_1_0 使用,dpy和sur对应于EGLDisplay 和 EGLSurface
// garbage data to catch improper use
mLists[i]->dpy = (hwc_display_t)0xDEADBEEF;
mLists[i]->sur = (hwc_surface_t)0xDEADBEEF;
} else {
mLists[i]->dpy = EGL_NO_DISPLAY;
mLists[i]->sur = EGL_NO_SURFACE;
}
}
}
/*对所有显示屏中所有Layer作合成准备(此时也可以开始发送合成的命令码下去,启动硬件合成,但不需要等待完成),hwcomposer需要正确汇报每个Layer的composetype,以告知SurfaceFlinger是否需要额外处理。
version 为 1.0 的驱动,只支持一个显示屏
version 为 1.1 的驱动,只支持物理显示屏
version 为 1.3 及以上的驱动,支持物理和虚拟显示屏*/
int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err));
if (err == NO_ERROR) {
// here we're just making sure that "skip" layers are set
// to HWC_FRAMEBUFFER and we're also counting how many layers
// we have of each type.
//
// If there are no window layers, we treat the display has having FB
// composition, because SurfaceFlinger will use GLES to draw the
// wormhole region.
for (size_t i=0 ; i<mNumDisplays ; i++) {
DisplayData& disp(mDisplayData[i]);
disp.hasFbComp = false;
disp.hasOvComp = false;
if (disp.list) {
//下面就是根据hwc汇报的composetype来设置相关属性
for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
hwc_layer_1_t& l = disp.list->hwLayers[i];
//ALOGD("prepare: %d, type=%d, handle=%p",
// i, l.compositionType, l.handle);
if (l.flags & HWC_SKIP_LAYER) {
l.compositionType = HWC_FRAMEBUFFER;
}
if (l.compositionType == HWC_FRAMEBUFFER) {
disp.hasFbComp = true;
}
if (l.compositionType == HWC_OVERLAY) {
disp.hasOvComp = true;
}
if (l.compositionType == HWC_CURSOR_OVERLAY) {
disp.hasOvComp = true;
}
}
if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
disp.hasFbComp = true;
}
} else {
disp.hasFbComp = true;
}
}
}
return (status_t)err;
}
1)遍历每一个显示屏,先取出framebufferTarget进行设置;
2)填充mList,DisplayData的list就是mList的一个组员,hwc_display_contents_1*,上面createWorkList讲过;
3)根据hwc版本初始化dpy和surface,或者outbuf;
4)调用hwc_composer_device_1 的set函数,对所有显示屏中所有Layer作合成准备(此时也可以开始发送合成的命令码下去,启动硬件合成,但不需要等待完成),hwcomposer需要正确汇报每个Layer的composetype,以告知SurfaceFlinger是否需要额外处理。
5)下面就是根据hwc汇报的composetype来设置相关属性,关于不同type再次贴一遍:1
2
3
4
5
6
7/*
* HWC_FRAMEBUFFER_TARGET:该Layer是3D合成的目标Layer
* HWC_FRAMEBUFFER:hwcomposer无法处理此Layer,该Layer需要走3D合成流程,用OpenGL绘制
* HWC_OVERLAY:该Layer为硬件合成器所处理,不需要OpenGLES去渲染
* HWC_SIDEBAND:该Layer为视频的边频带,需要硬件合成器作特殊处理,若不支持,OpenGL方式只能以一个色块替代,这个标志是外界(应用/驱动)调用窗口系统的perform方法配置的
* HWC_CURSOR_OVERLAY:该Layer可通过setCursorPositionAsync 方法改变坐标
*/
这就是最后一步,提交hwc,然后获得合成类型的步骤。
小结
这就是本节内容,太晚了,不想写总结了,先睡了~