Android SurfaceFlinger 学习之路(十)----SurfaceFlinger处理Layer更新

       上次我们分析了SurfaceFlinger的事务处理,对合成前接受上层改变SF和Layer的状态的事务做了统一处理,这节就沿着上次的末尾,继续分析Layer的更新流程。(又断了很久了,实在惭愧,很多事情总是身不由己~)

更新Layer Buffer

       前几节分析Vsync信号还没有分析完,这一节顺着处理事务的尾巴,处理Layer中Buffer的更新。顺着代码走的,就到了SurfaceFlinger的handlePageFlip函数。

handlePageFlip函数

       page flip是翻页的意思,就是说翻过所有的页面,检查每个Layer的更新。依然位于frameworks/native/serivice/surfaceflinger/SurfaceFlinger.cpp中:

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
void SurfaceFlinger::handlePageFlip()
{
Region dirtyRegion;

bool visibleRegions = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);

// Store the set of layers that need updates. This set must not change as
// buffers are being latched, as this could result in a deadlock.
// Example: Two producers share the same command stream and:
// 1.) Layer 0 is latched
// 2.) Layer 0 gets a new frame
// 2.) Layer 1 gets a new frame
// 3.) Layer 1 is latched.
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display.
Vector<Layer*> layersWithQueuedFrames;
//检查Layer是否需要更新
for (size_t i = 0, count = layers.size(); i<count ; i++) {
const sp<Layer>& layer(layers[i]);
//该Layer是否有 QUEUED buffer,上上一篇讲过,
//每当有queued buffer,Layer的onFrameAvailable函数会回调,然后将mQueuedFrames加1
if (layer->hasQueuedFrame())
//将需要更新的Layer存入这个数组
layersWithQueuedFrames.push_back(layer.get());
}
//遍历每一个需要更新的Layer,
//调用Layer的latchBuffer函数计算Layer的脏区域,
//最后修改Layer所在的Display上的脏区域
for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
Layer* layer = layersWithQueuedFrames[i];
const Region dirty(layer->latchBuffer(visibleRegions));
const Layer::State& s(layer->getDrawingState());
invalidateLayerStack(s.layerStack, dirty);
}

mVisibleRegionsDirty |= visibleRegions;
}

       只看这个函数还是挺简单的:
       1)检查每个Layer,找出需要更新Layer的,并存入数组。我们在Android SurfaceFlinger 学习之路(八)—-Surface管理图形缓冲区中讲过,当把Graphic Buffer 在app侧绘制完后会queue给BufferQueue,此时buffer状态为QUEUED,同时会通知Layer的onFrameAvailable回调去通知SF消费。Layer的onFrameAvailable函数如下,位于rameworks/native/services/surfaceflinger/Layer.cpp:

1
2
3
4
void Layer::onFrameAvailable() {
android_atomic_inc(&mQueuedFrames);//会将mQueuedFrames加1
mFlinger->signalLayerUpdate();
}

       相应的Layer的hasQueuedFrame函数位于frameworks/native/services/surfaceflinger/Layer.h中:

1
2
3
4
/*
* Returns if a frame is queued.
*/

bool hasQueuedFrame() const { return mQueuedFrames > 0 || mSidebandStreamChanged; }

       因此可以找出需要更新的Layer,然后存入layersWithQueuedFrames这个数组中。

       2)遍历每一个需要更新的Layer,用Layer的latchBuffer函数计算Layer的脏区域。这一步是核心,我们接下来会仔细分析。

       3)最后修改Layer所在的Display上的脏区域。这一步调用了invalidateLayerStack函数:

1
2
3
4
5
6
7
8
9
void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
const Region& dirty) {
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
if (hw->getLayerStack() == layerStack) {
hw->dirtyRegion.orSelf(dirty);
}
}
}

       先遍历所有的设备,然后找到和Layer的layerstack一样的设备,然后通过“或“运算,将Layer的更新区域加到DisplayDevice的dirtyRegion区域上。

       所以这个函数的核心就是Layer的latchBuffer函数调用,计算需要更新的苍区域。

计算Layer的脏区域

       latchBuffer函数比较长,我们分部查看:

Part.1 处理SidebandStream

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
Region Layer::latchBuffer(bool& recomputeVisibleRegions)
{
ATRACE_CALL();
//如果sideband surface改变了,表该Layer为视频的边频带,需要硬件合成器作特殊处理,
//然后将 mSidebandStreamChanged置为false
if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
// mSidebandStreamChanged was true
mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
// sideband的情况,需要重新 计算可视区域
recomputeVisibleRegions = true;

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

Region outDirtyRegion;
//如果Layer中有QUEUED帧
if (mQueuedFrames > 0) {

// if we've already called updateTexImage() without going through
// a composition step, we have to skip this layer at this point
// because we cannot call updateTeximage() without a corresponding
// compositionComplete() call.
// we'll trigger an update in onPreComposition().
if (mRefreshPending) {
return outDirtyRegion;
}

// Capture the old state of the layer for comparisons later
//注意这里使用的是DrawingState
const State& s(getDrawingState());
const bool oldOpacity = isOpaque(s);
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;

//。。。。。。

}

       这一部分处理了如果是sidebandstream的逻辑,该Layer为视频的边频带,需要硬件合成器作特殊处理,若不支持,OpenGL方式只能以一个色块替代,这个标志是外界(应用/驱动)调用窗口系统的perform方法配置的。

Part.2 定义Reject结构体

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
87
88
89
90
91
92
93
94
95
96
97
98
99
struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
Layer::State& front;//drawingState
Layer::State& current;//currentState
bool& recomputeVisibleRegions;
bool stickyTransformSet;
Reject(Layer::State& front, Layer::State& current,
bool& recomputeVisibleRegions, bool stickySet)
: front(front), current(current),
recomputeVisibleRegions(recomputeVisibleRegions),
stickyTransformSet(stickySet) {
}

virtual bool reject(const sp<GraphicBuffer>& buf,
const IGraphicBufferConsumer::BufferItem& item)
{

if (buf == NULL) {
return false;
}

uint32_t bufWidth = buf->getWidth();
uint32_t bufHeight = buf->getHeight();

// check that we received a buffer of the right size
// (Take the buffer's orientation into account)
//旋转90度
if (item.mTransform & Transform::ROT_90) {
swap(bufWidth, bufHeight);
}

bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
if (front.active != front.requested) {
//当app请求SF分配图形缓冲区时候,会传入requestWidth和requestHeight
//如果请求的w和h为0,则isFixedSize为true,此时就要用窗口的大小
//或者请求的w/h和传入的buffer的w/h相等
if (isFixedSize ||
(bufWidth == front.requested.w &&
bufHeight == front.requested.h))
{
// Here we pretend the transaction happened by updating the
// current and drawing states. Drawing state is only accessed
// in this thread, no need to have it locked
//我们假设事务已经提交更新了,current已经赋值给drawing,
//所以我们不用再去给DrawingState加锁
//将request的Geometry区域赋值给active
front.active = front.requested;

// We also need to update the current state so that
// we don't end-up overwriting the drawing state with
// this stale current state during the next transaction
//
// NOTE: We don't need to hold the transaction lock here
// because State::active is only accessed from this thread.
//下一次事务提交更新时候,还会讲下一次的current与drawing交换赋值,
//所以本次我们这里不终止用对这次drawing state对current的覆盖
current.active = front.active;

// recompute visible region
//重新计算可视区域
recomputeVisibleRegions = true;
}

//打印些许log
//如果传入了请求的w/h,并且不是粘性的(往后一直遗留的)转换
if (!isFixedSize && !stickyTransformSet) {
//但是请求的w/h和传入buffer的w/hb不一致
//那么就需要拒绝掉这个buffer
if (front.active.w != bufWidth ||
front.active.h != bufHeight) {
// reject this buffer
ALOGE("rejecting buffer: bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}",
bufWidth, bufHeight, front.active.w, front.active.h);
return true;
}
}

// if the transparent region has changed (this test is
// conservative, but that's fine, worst case we're doing
// a bit of extra work), we latch the new one and we
// trigger a visible-region recompute.
//如果透明区域也改变了,也需要更新current的透明区域region,原因同上
if (!front.activeTransparentRegion.isTriviallyEqual(
front.requestedTransparentRegion)) {
front.activeTransparentRegion = front.requestedTransparentRegion;

// We also need to update the current state so that
// we don't end-up overwriting the drawing state with
// this stale current state during the next transaction
//
// NOTE: We don't need to hold the transaction lock here
// because State::active is only accessed from this thread.
current.activeTransparentRegion = front.activeTransparentRegion;

// recompute visible region
//重新计算可视区域
recomputeVisibleRegions = true;
}

return false;
}
};

       Reject结构体的定义,reject方法判断是否拒绝掉传入的buffer,详细都在注释中写道。
       核心就是如果请求的w/h和传入buffer的w/h不一致,就会拒绝掉这个buffer。
       如果不拒绝,就更新current和drawing的状态,方便下一次transation处理状态更新,左后将recomputeVisibleRegions置为true,表示重新计算可视区域。

Part.3 更新纹理并处理结果

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
//创建一个Reject对象
Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0);
//更新纹理
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
mFlinger->mPrimaryDispSync);
//延迟显示
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
//延迟显示,触发下一个VSYNC, 即Buffer显示的时间还没到
mFlinger->signalLayerUpdate();
return outDirtyRegion;
}

// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
//减少mQueuedFrames的值
//如果还有Queued的Buffer,那么通知 SurfaceFlinger在下一个VSYNC时进行更新
if (android_atomic_dec(&mQueuedFrames) > 1) {
mFlinger->signalLayerUpdate();
}
//发生了异常
if (updateResult != NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
return outDirtyRegion;
}

// update the active buffer
//mActiveBuffer表示马上要显示的buffer
//更新mActiveBuffer,得到现在需要输出的图像数据
mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
if (mActiveBuffer == NULL) {
//异常发生
// this can only happen if the very first buffer was rejected.
return outDirtyRegion;
}
//即将进入 refresh的阶段
mRefreshPending = true;
mFrameLatencyNeeded = true;
//如果是第一次接收到Buffer, 需要重新计算可视区域
if (oldActiveBuffer == NULL) {
// the first time we receive a buffer, we need to trigger a
// geometry invalidation.
recomputeVisibleRegions = true;
}

Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
if ((crop != mCurrentCrop) ||
(transform != mCurrentTransform) ||
(scalingMode != mCurrentScalingMode))
{
//保存最新的 crop 与transform 这些变量
mCurrentCrop = crop;
mCurrentTransform = transform;
mCurrentScalingMode = scalingMode;
recomputeVisibleRegions = true;
}
//最新的buffer和上一个渲染的buffer的尺寸不一样的,这时需要重新计算可视化区域
if (oldActiveBuffer != NULL) {
uint32_t bufWidth = mActiveBuffer->getWidth();
uint32_t bufHeight = mActiveBuffer->getHeight();
if (bufWidth != uint32_t(oldActiveBuffer->width) ||
bufHeight != uint32_t(oldActiveBuffer->height)) {
recomputeVisibleRegions = true;
}
}
//透明度相关
mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
if (oldOpacity != isOpaque(s)) {
recomputeVisibleRegions = true;
}

// FIXME: postedRegion should be dirty & bounds
//计算出脏区域
Region dirtyRegion(Rect(s.active.w, s.active.h));

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

       part3最核心的就是更新纹理,之后就是对于返回结果的处理。所以步骤就分两步:
       1)updateTexImage更新纹理。这一步比较重要,我们接下来单独分析。
       2)处理更新纹理的结果。
       延迟显示,触发下一个VSYNC, 即Buffer显示的时间还没到;减少mQueuedFrames的值,如果还有Queued的Buffer,那么通知 SurfaceFlinger在下一个VSYNC时进行更新。
       如果更新纹理发生了异常、第一次接收到buffer、crop和transform区域发生改变、最新的buffer和上一个渲染的buffer的尺寸不一样的、透明度区域发生改变,都需要重新可视化区域。
       最后返回计算出的脏区域。

更新纹理

       我们单独分析更新纹理,SurfaceFlingerConsumer的updateTexImage函数,位于frameworks/native/services/surfaceflinger/SurfaceFlingerConsumer.cpp:

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

status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
const DispSync& dispSync)
{
ATRACE_CALL();
ALOGV("updateTexImage");
Mutex::Autolock lock(mMutex);

if (mAbandoned) {//EGL没有初始化
ALOGE("updateTexImage: GLConsumer is abandoned!");
return NO_INIT;
}

// Make sure the EGL state is the same as in previous calls.
//检查EGL的状态是否ok
status_t err = checkAndUpdateEglStateLocked();
if (err != NO_ERROR) {
return err;
}

BufferQueue::BufferItem item;

// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
//获得要显示出来的Buffer
//a, 如果上层canvas绘图,获取到的fencefd为-1
//b, 上层opengl绘图,获取到的fencefd不为-1
err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
//处理获取buffer异常的状况
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
err = NO_ERROR;
} else if (err == BufferQueue::PRESENT_LATER) {
// return the error, without logging
} else {
ALOGE("updateTexImage: acquire failed: %s (%d)",
strerror(-err), err);
}
return err;
}


// We call the rejecter here, in case the caller has a reason to
// not accept this buffer. This is used by SurfaceFlinger to
// reject buffers which have the wrong size
int buf = item.mBuf;
// 检查是否需要 reject buffer,如果尺寸大小不对,就拒绝掉这个buffer
if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
//如果拒绝了这个buffer,就要释放它
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
return NO_ERROR;
}

// Release the previous buffer.
// 每次只能处理一个graphic buffer,要将上一次对应的buffer先release了,供别人使用
//首先创建一个release fence,
//将release fence传递给BufferQueue中的slot对应的mSlots[slot]的mFence
// 创建GLConsumer里新的EGLImage
err = updateAndReleaseLocked(item);
if (err != NO_ERROR) {
return err;
}
//4.4和以后已经不走这个if了,会在Layer::onDraw中去创建纹理
if (!SyncFeatures::getInstance().useNativeFenceSync()) {
// Bind the new buffer to the GL texture.
//
// Older devices require the "implicit" synchronization provided
// by glEGLImageTargetTexture2DOES, which this method calls. Newer
// devices will either call this in Layer::onDraw, or (if it's not
// a GL-composited layer) not at all.
//绑定EglImage到GL texture
err = bindTextureImageLocked();
}

return err;
}

       在这里面会去acquire buffer,然后acquire到的buffer就会去用来合成。主要做的事情:
       1)acquire一个新的buffer;
       2)将上一次对应的buffer先release了,并为上次的buffer创建一个release fence,将该release fence传递给BufferQueue中的slot对应的mSlots[slot]的mFence;
       3)更新mCurrentTexture和mCurrentTextureBuf为这次acquire到的buffer以及slot。
       目前acquire fencefd还没使用,因为还未去合成这个layer,没到用layer中数据的时候。

       这里有几个重要的步骤,我们分模块分析。

获取buffer

       之前我们讲过buffer的状态迁移,又如下一幅图:

buffer状态迁移

       之前讲buffer queued进入BufferQueue,然后等等待SF消费。所以SF本次acquire buffer,buffer状态迁移为ACQUIRED。

       顺着上面的步骤,查看acquireBufferLocked函数。不过之前我们先看看参数中computeExpectedPresent函数计算下一次vsync信号到来的时间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync)
{
// The HWC doesn't currently have a way to report additional latency.
// Assume that whatever we submit now will appear right after the flip.
// For a smart panel this might be 1. This is expressed in frames,
// rather than time, because we expect to have a constant frame delay
// regardless of the refresh rate.
const uint32_t hwcLatency = 0;

// Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
//调用DispSync的dispSync.computeNextRefresh计算下一次刷新时间
const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);

// The DispSync time is already adjusted for the difference between
// vsync and reported-vsync (PRESENT_TIME_OFFSET_FROM_VSYNC_NS), so
// we don't need to factor that in here. Pad a little to avoid
// weird effects if apps might be requesting times right on the edge.
nsecs_t extraPadding = 0;
if (VSYNC_EVENT_PHASE_OFFSET_NS == 0) {
extraPadding = 1000000; // 1ms (6% of 60Hz)
}

return nextRefresh + extraPadding;
}

       计算下一次vsync_sf时间,位于frameworks/native/services/surfaceflinger/DispSync.cpp中:

1
2
3
4
5
nsecs_t DispSync::computeNextRefresh(int periodOffset) const {
Mutex::Autolock lock(mMutex);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
return (((now - mPhase) / mPeriod) + periodOffset + 1) * mPeriod + mPhase;
}

       就是一个屏幕刷新周期之后的时间。

       获得了这个实参,然后就查看获取buffer的函数acquireBufferLocked:

1
2
3
4
5
6
7
8
status_t SurfaceFlingerConsumer::acquireBufferLocked(
BufferQueue::BufferItem *item, nsecs_t presentWhen) {
status_t result = GLConsumer::acquireBufferLocked(item, presentWhen);
if (result == NO_ERROR) {
mTransformToDisplayInverse = item->mTransformToDisplayInverse;
}
return result;
}

       这里调用了GLConsumer的acquireBufferLocked函数,位于frameworks/native/libs/gui/GLConsumer.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item,
nsecs_t presentWhen) {
//调用ConsumerBase的acquireBufferLocked函数
status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
if (err != NO_ERROR) {
return err;
}

// If item->mGraphicBuffer is not null, this buffer has not been acquired
// before, so any prior EglImage created is using a stale buffer. This
// replaces any old EglImage with a new one (using the new buffer).
//如果这个buffer已经被acquired,它的图形缓冲区buffer不为空,
//那么一些以前的EglImage就会使用过时的buffer
//因此创建GLConsumer里新的EGLImage
if (item->mGraphicBuffer != NULL) {
int slot = item->mBuf;
mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
}

return NO_ERROR;
}

       这里又调用ConsumerBase的acquireBufferLocked函数去获取buffer。之后,如果这个buffer已经被acquired,它的图形缓冲区buffer不为空,那么一些以前的EglImage就会使用过时的buffer,因此创建GLConsumer里新的EGLImage。
       我们继续查看ConsumerBase的acquireBufferLocked函数,位于rameworks/native/libs/gui/ConsumerBase.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item,
nsecs_t presentWhen) {
//又通过binder IPC调用了BufferQueueConsumer的acquireBuffer函数
status_t err = mConsumer->acquireBuffer(item, presentWhen);
if (err != NO_ERROR) {
return err;
}
//获取到buffer之后,然后赋值给对应mSlots数组中index的BufferSlot
if (item->mGraphicBuffer != NULL) {
mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
}

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

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

return OK;
}

       这里又通过binder IPC调用了BufferQueueConsumer的acquireBuffer函数,位于frameworks/native/libs/gui/BufferQueueConsumer.cpp:

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent) {
ATRACE_CALL();
Mutex::Autolock lock(mCore->mMutex);

// Check that the consumer doesn't currently have the maximum number of
// buffers acquired. We allow the max buffer count to be exceeded by one
// buffer so that the consumer can successfully set up the newly acquired
// buffer before releasing the old one.
//统计mActiveBuffers中已经是 ACQUIRED 的Frame 个数
int numAcquiredBuffers = 0;
for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
//是否已经是 ACQUIRED 的Buffer
if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
++numAcquiredBuffers;
}
}
//异常检测
if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
return INVALID_OPERATION;
}

// Check if the queue is empty.
// In asynchronous mode the list is guaranteed to be one buffer deep,
// while in synchronous mode we use the oldest buffer.
if (mCore->mQueue.empty()) {
return NO_BUFFER_AVAILABLE;
}
//queue中的第一个 buffer
BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());

// If expectedPresent is specified, we may not want to return a buffer yet.
// If it's specified and there's more than one buffer queued, we may want
// to drop a buffer.
if (expectedPresent != 0) {
//一秒作为选择显示的buffer的范围条件
const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second

// The 'expectedPresent' argument indicates when the buffer is expected
// to be presented on-screen. If the buffer's desired present time is
// earlier (less) than expectedPresent -- meaning it will be displayed
// on time or possibly late if we show it as soon as possible -- we
// acquire and return it. If we don't want to display it until after the
// expectedPresent time, we return PRESENT_LATER without acquiring it.
//expectedPresent参数表示的是buffer被我们期望的显示时间。
//如果buffer自己的渴望显示时间早于被期望的时间,意味着它可以按自己渴望时间显示,
//但是也会迟到,比如我们获取了它去迅速返回了,这时候它显示就要迟到了,
//此时我们就要返回一个PRESENT_LATER标志让它在下一次vsync信号去处理。
//
// To be safe, we don't defer acquisition if expectedPresent is more
// than one second in the future beyond the desired present time
// (i.e., we'd be holding the buffer for a long time).
//安全起见,我们就不推迟采集被期望的时间大于buffer渴望显示时间超过1秒的buffer了,
//例如,我们长时间持有一个buffer不释放,就会让expectedPresent很大
//
// NOTE: Code assumes monotonic time values from the system clock
// are positive.

// Start by checking to see if we can drop frames. We skip this check if
// the timestamps are being auto-generated by Surface. If the app isn't
// generating timestamps explicitly, it probably doesn't want frames to
// be discarded based on them.
// 检查后面的 Queue, 找到最近需要显示的Buffer
while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
// If entry[1] is timely, drop entry[0] (and repeat). We apply an
// additional criterion here: we only drop the earlier buffer if our
// desiredPresent falls within +/- 1 second of the expected present.
// Otherwise, bogus desiredPresent times (e.g., 0 or a small
// relative timestamp), which normally mean "ignore the timestamp
// and acquire immediately", would cause us to drop frames.
//如果entry[1]是及时的,就出drop掉entry[0]的buffer,然后继续往后面选。
//我们额外应用一个准则在这里:如果entry[1]的buffer的 desired time落在期望显示时间误差1秒内,那么我们drop掉entry[0]
//
// We may want to add an additional criterion: don't drop the
// earlier buffer if entry[1]'s fence hasn't signaled yet.
//还有一个准则:如果entry[1]的fence还没有到来,不drop entry[1]的buffer
const BufferItem& bufferItem(mCore->mQueue[1]);
nsecs_t desiredPresent = bufferItem.mTimestamp;
//如果这个buffer显示的时间在expected之后(garbage),或者将来的1s内会,那么不drop掉上一个.
// break掉直接显示上一个buffer
if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
desiredPresent > expectedPresent) {
// This buffer is set to display in the near future, or
// desiredPresent is garbage. Either way we don't want to drop
// the previous buffer just to get this on the screen sooner.
BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
PRId64 " (%" PRId64 ") now=%" PRId64,
desiredPresent, expectedPresent,
desiredPresent - expectedPresent,
systemTime(CLOCK_MONOTONIC));
break;
}

BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
" size=%zu",
desiredPresent, expectedPresent, mCore->mQueue.size());
//如果上一个需要drop的buffer仍然在slots中,那么标记他为FREE状态
if (mCore->stillTracking(front)) {
// Front buffer is still in mSlots, so mark the slot as free
mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
}
//上一个已经没有必要显示了, 重新找一个显示的
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
}

// See if the front buffer is due
buffer要显示的时间还没到,那么标记为PRESENT_LATER,下一帧处理
nsecs_t desiredPresent = front->mTimestamp;
if (desiredPresent > expectedPresent &&
desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
" (%" PRId64 ") now=%" PRId64,
desiredPresent, expectedPresent,
desiredPresent - expectedPresent,
systemTime(CLOCK_MONOTONIC));
return PRESENT_LATER;
}

BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
"(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
desiredPresent - expectedPresent,
systemTime(CLOCK_MONOTONIC));
}

int slot = front->mSlot;
*outBuffer = *front;
ATRACE_BUFFER_INDEX(slot);

BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
slot, front->mFrameNumber, front->mGraphicBuffer->handle);
// If the front buffer is still being tracked, update its slot state
//即将要显示的Buffer没有过期,就要更新状态变为 ACQUIRED
if (mCore->stillTracking(front)) {
mSlots[slot].mAcquireCalled = true;//BUFFER的状态已经是 ACQUIRED 的了
mSlots[slot].mNeedsCleanupOnRelease = false;
mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
mSlots[slot].mFence = Fence::NO_FENCE;
}

// If the buffer has previously been acquired by the consumer, set
// mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
// on the consumer side
//如果buffer之前已经被获取了,设置mGraphicBuffer变量为NULL,避免consumer不必要的二次映射
if (outBuffer->mAcquireCalled) {
outBuffer->mGraphicBuffer = NULL;
}
//将Buffer从 BufferQueueCore列队里移除
mCore->mQueue.erase(front);

// We might have freed a slot while dropping old buffers, or the producer
// may be blocked waiting for the number of buffers in the queue to
// decrease.
//我们在第七节讲过,当dequeue buffer时候,slots有可能没有free的buffer可用,
//因此会在producer那儿等待,所以我们这里释放一个slot时候就要去唤醒那儿的lock
mCore->mDequeueCondition.broadcast();

ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());

return NO_ERROR;
}

       这也就是我们Buffer迁移状态中ACQUIRED状态的流程,Acquire一个需要处理的Buffer。根据前面对Buffer状态迁移的分析,当消费者想处理一块buffer时,它首先要向BufferQueue做acquire申请。那么BufferQueue怎么知道当前要处理哪一个Buffer呢?这是因为其内部维护有一个Fifo先入先出队列。一旦有buffer被enqueue后,就会压入队尾;每次acquire就从队头取最前面的元素进行处理,完成之后就将其从队列移除。
       代码流程如下:
       1)统计mActiveBuffers中已经是 ACQUIRED 的Frame 个数,并且检测异常;
       2)queue中的第一个 buffer,一秒作为选择显示的buffer的范围条件。如果这个entry[1]显示的时间在expected之后(garbage),或者将来的1s内会,那么不drop掉上一个,直接break掉,显示entry[0];
       3)如果entry[1]是及时的,就出drop掉entry[0]的buffer,然后继续往后面选;
       4)buffer要显示的时间还没到,那么标记为PRESENT_LATER,下一帧处理;
       5)更新buffer状态,并从队列中移除。

释放buffer并更新状态

       Acquire到的buffer封装在BufferItem中,item.mBuf代表它在BufferSlot中的序号。正常情况下item.mGraphicBuffer都不为空,我们将它记录到mEGLSlots[buf].mGraphicBuffer中,以便后续操作。
       消费者一旦处理完Buffer后,就可以将其release了。此后这个buffer就又恢复FREE状态,以供生产者再次dequeue使用。
       那么我们就看看这个释放过程,更新纹理中释放过程,updateAndReleaseLocked函数,实现位于GLConsumer中:

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
87
88
89
90
91

status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item)
{
status_t err = NO_ERROR;
//招呼slot
int buf = item.mBuf;

if (!mAttached) {//Open GL ES 是否attach
ST_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL "
"ES context");
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
mEglDisplay, EGL_NO_SYNC_KHR);
return INVALID_OPERATION;
}

// Confirm state.
//检测EGL状态
err = checkAndUpdateEglStateLocked();
if (err != NO_ERROR) {
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
mEglDisplay, EGL_NO_SYNC_KHR);
return err;
}

// Ensure we have a valid EglImageKHR for the slot, creating an EglImage
// if nessessary, for the gralloc buffer currently in the slot in
// ConsumerBase.
// We may have to do this even when item.mGraphicBuffer == NULL (which
// means the buffer was previously acquired).
//创建 EGLImage ,此时 mEglImage 已经有了
//acquireBufferLocked中找到的即将要显示的 BufferItem 的 GraphicBuffer
err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
if (err != NO_ERROR) {
ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
mEglDisplay, buf);
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
mEglDisplay, EGL_NO_SYNC_KHR);
return UNKNOWN_ERROR;
}

// Do whatever sync ops we need to do before releasing the old slot.
// 在释放老的buffer前,先给添加一个release fence,有可能还在使用
err = syncForReleaseLocked(mEglDisplay);
if (err != NO_ERROR) {
// Release the buffer we just acquired. It's not safe to
// release the old buffer, so instead we just drop the new frame.
// As we are still under lock since acquireBuffer, it is safe to
// release by slot.
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
mEglDisplay, EGL_NO_SYNC_KHR);
return err;
}

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

// release old buffer
// 先把老的buffer,release了
// 如果是第一次为mCurrentTexture为BufferQueue::INVALID_BUFFER_SLOT,-1
// 将release fence传递给BufferQueue中的slot对应的mSlots[slot]的mFence
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
//释放buffer
status_t status = releaseBufferLocked(
mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
if (status < NO_ERROR) {
ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
strerror(-status), status);
err = status;
// keep going, with error raised [?]
}
}

// Update the GLConsumer state.
// 更新 GLConsumer 状态
//更新这次acquire到的buffer到mCurrentTexture和mCurrentTextureImage
mCurrentTexture = buf;
mCurrentTextureImage = mEglSlots[buf].mEglImage;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
mCurrentTimestamp = item.mTimestamp;
mCurrentFence = item.mFence;
mCurrentFrameNumber = item.mFrameNumber;
//对当前的buffer进行矩阵变换处理
computeCurrentTransformMatrixLocked();

return err;
}

       updateAndReleaseLocked这个函数释放了buffer,然后更新了mCurrentTexture mCurrentTextureImage等。步骤如下:
       1)检测Open GL是否连接,EGL状态是否OK;
       2)创建 EGLImage (此时 mEglImage 已经有了,acquireBufferLocked中找到的即将要显示的 BufferItem 的 GraphicBuffer);
       3)释放老的buffer前,先给添加一个release fence,有可能还在使用(我们本届不讨论Fence相关内容,以后有机会会仔细研究);
       4)释放buffer(这个接下来仔细分析);
       5)更新 GLConsumer 状态,更新这次acquire到的buffer到mCurrentTexture和mCurrentTextureImage。

       核心是释放buffer,因此我们看看releaseBufferLocked函数:

1
2
3
4
5
6
7
8
9
10
11
12
status_t GLConsumer::releaseBufferLocked(int buf,
sp<GraphicBuffer> graphicBuffer,
EGLDisplay display, EGLSyncKHR eglFence) {
// release the buffer if it hasn't already been discarded by the
// BufferQueue. This can happen, for example, when the producer of this
// buffer has reallocated the original buffer slot after this buffer
// was acquired.
status_t err = ConsumerBase::releaseBufferLocked(
buf, graphicBuffer, display, eglFence);
mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
return err;
}

       这里又调用了ConsumerBase的releaseBufferLocked函数:

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
status_t ConsumerBase::releaseBufferLocked(
int slot, const sp<GraphicBuffer> graphicBuffer,
EGLDisplay display, EGLSyncKHR eglFence) {
// If consumer no longer tracks this graphicBuffer (we received a new
// buffer on the same slot), the buffer producer is definitely no longer
// tracking it.
if (!stillTracking(slot, graphicBuffer)) {
return OK;
}

CB_LOGV("releaseBufferLocked: slot=%d/%" PRIu64,
slot, mSlots[slot].mFrameNumber);
//release 老buffer的时候,会传入一个mSlots[slot].mFence,即release fence
//调用BufferQueueConsumer的releaseBuffer函数
status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber,
display, eglFence, mSlots[slot].mFence);
//如果buffer已经过时了但还位于slot中,那么释放他
if (err == IGraphicBufferConsumer::STALE_BUFFER_SLOT) {
freeBufferLocked(slot);
}

mSlots[slot].mFence = Fence::NO_FENCE;

return err;
}

void ConsumerBase::freeBufferLocked(int slotIndex) {
CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
mSlots[slotIndex].mGraphicBuffer = 0;
mSlots[slotIndex].mFence = Fence::NO_FENCE;
mSlots[slotIndex].mFrameNumber = 0;
}

       继而又调用了BufferQueueConsumer的releaseBuffer函数:

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
status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
EGLSyncKHR eglFence) {
ATRACE_CALL();
ATRACE_BUFFER_INDEX(slot);

if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
releaseFence == NULL) {
return BAD_VALUE;
}

sp<IProducerListener> listener;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);

// If the frame number has changed because the buffer has been reallocated,
// we can ignore this releaseBuffer for the old buffer
//如果frameNumber改变了,意味着buffer被重新申请了,
//所以我们要要标记这个老的buffer为STABLE,然后释放掉老的buffer
if (frameNumber != mSlots[slot].mFrameNumber) {
return STALE_BUFFER_SLOT;
}

// Make sure this buffer hasn't been queued while acquired by the consumer
//当consumer去acquire buffer时候,确保这个buffer不在BufferQueue当中
BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
while (current != mCore->mQueue.end()) {
if (current->mSlot == slot) {
BQ_LOGE("releaseBuffer: buffer slot %d pending release is "
"currently queued", slot);
return BAD_VALUE;
}
++current;
}
//如果这个buffer被Acquired过了,那么释放他为FREE
if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
mSlots[slot].mEglDisplay = eglDisplay;
mSlots[slot].mEglFence = eglFence;
mSlots[slot].mFence = releaseFence;
mSlots[slot].mBufferState = BufferSlot::FREE;
listener = mCore->mConnectedProducerListener;
BQ_LOGV("releaseBuffer: releasing slot %d", slot);
} else if (mSlots[slot].mNeedsCleanupOnRelease) {//如果还存于slot中,是旧的buffer,那么释放他
BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d "
"(state = %d)", slot, mSlots[slot].mBufferState);
mSlots[slot].mNeedsCleanupOnRelease = false;
return STALE_BUFFER_SLOT;
} else {//异常
BQ_LOGV("releaseBuffer: attempted to release buffer slot %d "
"but its state was %d", slot, mSlots[slot].mBufferState);
return BAD_VALUE;
}
//同上面逻辑,dequeue buffer时候可能会wait,这里唤醒wait锁
mCore->mDequeueCondition.broadcast();
} // Autolock scope

// Call back without lock held
//回调onBufferReleased函数,调用ConsumerBase::onBuffersReleased
if (listener != NULL) {
listener->onBufferReleased();
}

return NO_ERROR;
}

       释放buffer的逻辑如下:
       1)异常检测。slot 的index是否合法,是否因为reallocate buffer导致frameNumber改变,当consumer去acquire buffer时候它是否在不在BufferQueue当中;
       2)释放buffer。如果这个buffer被Acquired过了,那么释放他为FREE;如果还存于slot中,是旧的buffer,那么释放他;异常或者状态异常;
       3)唤醒dequeue buffer时候的wait lock,回调ConsumerBase::onBuffersReleased,通知buffer释放。

       以上就释放buffer的流程。

       结合上一节内容,经过handleTransaction handlePageFlip两个函数处理,SurfaceFlinger中无论是Layer属性的变化还是图像的变化都处理好了,只等VSync信号到来就可以输出了。
       Layer更新中比较重要的就是Buffer状态的迁移,本节主要涉及了Buffer的ACQUIRED和RELEASED状态,这也正好完善了下图的剩下两个流程。

buffer状态迁移

       本节内容画一幅时序图如下:

handlePageFlip

小结

       本节主要处理Layer的更新逻辑,先计算layer的脏区域,再更新纹理。更新纹理又包含获取了buffer状态迁移的剩下两环:ACQUIRED、RELEADED。
       至此,处理Vsync信号到来时候的前两环已经处理完结了,即SurfaceFlinger中onMessageReceived回调函数的INVALIDATE CASE。下一节开始就是真正的合成阶段——REFRESH,这是个很复杂的流程,我们仍然会一一分析。

妹子

       (不如意事常八九,可与语人无二三。)

坚持技术分享,您的支持将鼓励我继续创作!