SurfaceFlinger合成流程(二)
SurfaceFlinger合成流程
MessageQueue中分发两个消息,一个INVALIDATE,一个REFRESH,SurfaceFlinger对这两个消息的响应过程,就是合成的过程。
消息INVALIDATE处理
在onFrameAvailable时,调用signalLayerUpdate,将触发INVALIDATE消息。SurfaceFlinger收到这个消息的处理如下:
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
bool frameMissed = !mHadClientComposition &&
mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getSignalTime() ==
Fence::SIGNAL_TIME_PENDING);
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
if (mPropagateBackpressure && frameMissed) {
signalLayerUpdate();
break;
}
updateVrFlinger();
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded) {
signalRefresh();
}
break;
}
case MessageQueue::REFRESH: {
handleMessageRefresh();
break;
}
}
}
在INVALIDATE过程中,主要做以下处理:
- 对丢帧的处理
如果丢帧,且mPropagateBackpressure为true,mPropagateBackpressure表示显示给压力了。显示说,太慢了,都丢帧了,给点压力,上层赶紧处理。mPropagateBackpressure是在SurfaceFlinger的构造函数中初始化的,受debug.sf.disable_backpressure
属性的控制。
property_get("debug.sf.disable_backpressure", value, "0");
mPropagateBackpressure = !atoi(value);
- 更新VR updateVrFlinger
这个只有在VR模式下才会起作用,我们这里先不管VR的事。
- 处理Transition
Transition的处理,前面我们已经说过,只是当时不清楚是什么时候触发的,现在清楚了。Vsync到来后,触发INVALIDATE消息时先去处理Transition。处理的过程就是前面已经说过的handleMessageTransaction,有需要可以回头去看看。这个过程就是处理应用传过来的各种Transition,需要记住的是在commit Transition时,又个状态的更替,mCurrentState赋值给了mDrawingState。
void SurfaceFlinger::commitTransaction()
{
... ...
mDrawingState = mCurrentState;
mDrawingState.traverseInZOrder([](Layer* layer) {
layer->commitChildList();
});
... ...
}
所以SurfaceFlinger两个状态:
mCurrentState状态, 准备数据,应用传过来的数据保存在mCurrentState中。
mDrawingState状态,进程合成状态,需要进行合成的数据保存在mDrawingState中。
也就是说,每次合成时,先更新一下状态数据。每一层Layer也需要去更新状态数据。
- 处理Invalidate
这是一个重要的流程,handleMessageInvalidate函数如下:
bool SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
return handlePageFlip();
}
主要是调用handlePageFlip,做Page的Flip。
bool SurfaceFlinger::handlePageFlip()
{
ALOGV("handlePageFlip");
nsecs_t latchTime = systemTime();
bool visibleRegions = false;
bool frameQueued = false;
bool newDataLatched = false;
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->hasQueuedFrame()) {
frameQueued = true;
if (layer->shouldPresentNow(mPrimaryDispSync)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
layer->useEmptyDamage();
}
} else {
layer->useEmptyDamage();
}
});
for (auto& layer : mLayersWithQueuedFrames) {
const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
layer->useSurfaceDamage();
invalidateLayerStack(layer, dirty);
if (layer->isBufferLatched()) {
newDataLatched = true;
}
}
mVisibleRegionsDirty |= visibleRegions;
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
signalLayerUpdate();
}
// Only continue with the refresh if there is actually new work to do
return !mLayersWithQueuedFrames.empty() && newDataLatched;
}
mLayersWithQueuedFrames,用于标记那些已经有Frame的Layer,这得从Layer的onFrameAvailable说起。
void BufferLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(),
item.mFrameNumber);
// Reset the frame number tracker when we receive the first buffer after
// a frame number reset
if (item.mFrameNumber == 1) {
mLastFrameNumberReceived = 0;
}
// Ensure that callbacks are handled in order
while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
ms2ns(500));
if (result != NO_ERROR) {
ALOGE("[%s] Timed out waiting on callback", mName.string());
}
}
mQueueItems.push_back(item);
android_atomic_inc(&mQueuedFrames);
// Wake up any pending callbacks
mLastFrameNumberReceived = item.mFrameNumber;
mQueueItemCondition.broadcast();
}
mFlinger->signalLayerUpdate();
}
onFrameAvailable时,先将Buffer的窗口属性保存在mInterceptor中,这里我们暂时不看,记得标记一下。然后对FrameNumber进行处理,一是确保FrameNumber被重置时,重置mLastFrameNumberReceived,二时,确保FrameNumber的顺序。之后,将新过来的BufferItem,push到mQueueItems中,对mQueuedFrames数进行+1。最后才触发SurfaceFlinger进行signalLayerUpdate。
回到handlePageFlip。所以,对于触发SurfaceFlinger进行signalLayerUpdate的Layer,hasQueuedFrame为true,是有Queued的Frame的。
但是mLayersWithQueuedFrames还要一个条件,shouldPresentNow。
bool BufferLayer::shouldPresentNow(const DispSync& dispSync) const {
if (mSidebandStreamChanged || mAutoRefresh) {
return true;
}
Mutex::Autolock lock(mQueueItemLock);
if (mQueueItems.empty()) {
return false;
}
auto timestamp = mQueueItems[0].mTimestamp;
nsecs_t expectedPresent = mConsumer->computeExpectedPresent(dispSync);
// Ignore timestamps more than a second in the future
bool isPlausible = timestamp < (expectedPresent + s2ns(1));
ALOGW_IF(!isPlausible,
"[%s] Timestamp %" PRId64 " seems implausible "
"relative to expectedPresent %" PRId64,
mName.string(), timestamp, expectedPresent);
bool isDue = timestamp < expectedPresent;
return isDue || !isPlausible;
}
在shouldPresentNow的判断逻辑中,首先根据DispSync,去计算期望显示的时间。再看看Buffer的时间戳和期望显示的时间,如果Buffer的时间还没有到,且和期望显示的时间之间差不到1秒,那么shouldPresentNow成立。该Layer标记为mLayersWithQueuedFrames;否则,Layer使用空的DamageRegion。记住这个DamageRegion。
void BufferLayer::useEmptyDamage() {
surfaceDamageRegion.clear();
}
继续handlePageFlip函数分析。
- 对mLayersWithQueuedFrames标记的Layer进行处理
首先,通过latchBuffer获取Layer的Buffer;再更新Surface的Damage;再通过invalidateLayerStack去刷新脏区域,验证LayerStack。记住LayerStack这个概念。处理这块稍后继续~~~
注意这里重新signalLayerUpdate的逻辑。
if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
signalLayerUpdate();
}
有BufferQueue过来,但是还没有到显示时间(mLayersWithQueuedFrames为空),或者没有获取到Buffer。重新触发一次更新~
注意handlePageFlip的返回值,有Layer要显示,且获取到Buffer时,才返回true。注意这里的mVisibleRegionsDirty,mVisibleRegionsDirty,脏区域,表示可见