先从SurfaceFlinger中分析绘制流程
收到case MessageQueue::INVALIDATE开始
case MessageQueue::INVALIDATE: {
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
// repaint
signalRefresh();
}
break;
}
主要做了几件事情
1 handleMessageTransaction处理事务,也就是客户端告诉我们一些数据发生变化了,我们要把这些信息收集起来,进行状态切换
2 handleMessageInvalidate进行页面反转(主要是对buffer的处理)
3 第三步就是根据前两步的出理结果决定是否要刷新缓冲区
下面我们一一详细分析三个步骤
步骤一:
bool SurfaceFlinger::handleMessageTransaction() {
uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
if (transactionFlags) {
handleTransaction(transactionFlags);
return true;
}
return false;
}
首先偷看下是否有外部作用使当前的状态发生变化,如果有则进行事务处理,这里我们直接分析handleTransaction函数
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
// here we keep a copy of the drawing state (that is the state that's
// going to be overwritten by handleTransactionLocked()) outside of
// mStateLock so that the side-effects of the State assignment
// don't happen with mStateLock held (which can cause deadlocks).
State drawingState(mDrawingState);
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
// Here we're guaranteed that some transaction flags are set
// so we can call handleTransactionLocked() unconditionally.
// We call getTransactionFlags(), which will also clear the flags,
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
}
注意这个函数全程持有 Mutex::Autolock _l(mStateLock);锁,所以在这个函数执行的时候事务不会被其他地方更改,
然后清除我们要处理的flags,之后使用handleTransactionLocked处理事务
最后使用invalidateHwcGeometry()函数更新mHwWorkListDirty,该变量用于通知hwc模块重新创建WorkList
我们把重点放在void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)函数,这个函数比较长我们也分段阅读
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
// Notify all layers of available frames
for (size_t i = 0; i < count; ++i) {
currentLayers[i]->notifyAvailableFrames();
}
/*
* Traversal of the children
* (perform the transaction for each of them if needed)
*/
if (transactionFlags & eTraversalNeeded) {
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
}
}
第一部分 首先currentLayers[i]->notifyAvailableFrames(); 函数我们这里先不分析
eTraversalNeeded,eTraversalNeeded表示layer数据发生变化,如果设置了该标志,就要对每个有变化的layer处理.
那么如何判断layer是否有发生变化呢,使用layer->getTransactionFlags(eTransactionNeeded)进行处理.
在layer中也有个mTransactionFlags标志,如果layer发生变化就会设置相应的位
如果layer发生变化就要处理layer的事务,采用layer->doTransaction(0)函数处理
下面分析layer的doTransaction函数
uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL();
pushPendingState();
Layer::State c = getCurrentState();
if (!applyPendingStates(&c)) {
return 0;
}
const Layer::State& s(getDrawingState());
const bool sizeChanged = (c.requested.w != s.requested.w) ||
(c.requested.h != s.requested.h);
if (sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
ALOGD_IF(DEBUG_RESIZE,
"doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n"
" current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} }}\n"
" drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} }}\n",
this, getName().string(), mCurrentTransform,
getEffectiveScalingMode(),
c.active.w, c.active.h,
c.crop.left,
c.crop.top,
c.crop.right,
c.crop.bottom,
c.crop.getWidth(),
c.crop.getHeight(),
c.requested.w, c.requested.h,
s.active.w, s.active.h,
s.crop.left,
s.crop.top,
s.crop.right,
s.crop.bottom,
s.crop.getWidth(),
s.crop.getHeight(),
s.requested.w, s.requested.h);
// record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
mSurfaceFlingerConsumer->setDefaultBufferSize(
c.requested.w, c.requested.h);
}
const bool resizePending = (c.requested.w != c.active.w) ||
(c.requested.h != c.active.h);
if (!isFixedSize()) {
if (resizePending && mSidebandStream == NULL) {
// don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// the drawing state will be updated only once we receive a buffer
// with the correct size.
//
// in particular, we want to make sure the clip (which is part
// of the geometry state) is latched together with the size but is
// latched immediately when no resizing is involved.
//
// If a sideband stream is attached, however, we want to skip this
// optimization so that transactions aren't missed when a buffer
// never arrives
flags |= eDontUpdateGeometryState;
}
}
// always set active to requested, unless we're asked not to
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
Layer::State& editCurrentState(getCurrentState());
if (mFreezePositionUpdates) {
float tx = c.active.transform.tx();
float ty = c.active.transform.ty();
c.active = c.requested;
c.active.transform.set(tx, ty);
editCurrentState.active = c.active;
} else {
editCurrentState.active = editCurrentState.requested;
c.active = c.requested;
}
}
if (s.active != c.active) {
// invalidate and recompute the visible regions if needed
flags |= Layer::eVisibleRegion;
}
if (c.sequence != s.sequence) {
// invalidate and recompute the visible regions if needed
flags |= eVisibleRegion;
this->contentDirty = true;
// we may use linear filtering, if the matrix scales us
const uint8_t type = c.active.transform.getType();
mNeedsFiltering = (!c.active.transform.preserveRects() ||
(type >= Transform::SCALE));
}
// If the layer is hidden, signal and clear out all local sync points so
// that transactions for layers depending on this layer's frames becoming
// visible are not blocked
if (c.flags & layer_state_t::eLayerHidden) {
Mutex::Autolock lock(mLocalSyncPointMutex);
for (auto& point : mLocalSyncPoints) {
point->setFrameAvailable();
}
mLocalSyncPoints.clear();
}
// Commit the transaction
commitTransaction(c);
return flags;
}
这个函数理解起来也比较困难,首先pushPendingState()函数
这个函数很有意思 为了实现一个deferTransactionUntil的功能,意思是延迟执行事务直到某个layer的某一帧到来.一般用在SurfaceView上面
用于和父窗口同步绘制的(就是一起准备数据绘制某一帧)
void Layer::pushPendingState() {
if (!mCurrentState.modified) {
return;
}
// If this transaction is waiting on the receipt of a frame, generate a sync
// point and send it to the remote layer.
if (mCurrentState.handle != nullptr) {
sp<IBinder> strongBinder = mCurrentState.handle.promote();
sp<Handle> handle = nullptr;
sp<Layer> handleLayer = nullptr;
if (strongBinder != nullptr) {
handle = static_cast<Handle*>(strongBinder.get());
handleLayer = handle->owner.promote();
}
if (strongBinder == nullptr || handleLayer == nullptr) {
ALOGE("[%s] Unable to promote Layer handle", mName.string());
// If we can't promote the layer we are intended to wait on,
// then it is expired or otherwise invalid. Allow this transaction
// to be applied as per normal (no synchronization).
mCurrentState.handle = nullptr;
} else {
auto syncPoint = std::make_shared<SyncPoint>(
mCurrentState.frameNumber);
if (handleLayer->addSyncPoint(syncPoint)) {
mRemoteSyncPoints.push_back(std::move(syncPoint));
} else {
// We already missed the frame we're supposed to synchronize
// on, so go ahead and apply the state update
mCurrentState.handle = nullptr;
}
}
// Wake us up to check if the frame has been received
setTransactionFlags(eTransactionNeeded);
}
mPendingStates.push_back(mCurrentState);
}
首先要执行pushPendingState的条件就是mCurrentState.modified==true,也就是当前状态有变化,在layer中有两个类型为State的变量,类似于双缓冲机制用于反转.分别是 State mCurrentState; 和State mDrawingState; mDrawingState是当前正在用于绘制的状态,mCurrentState是用于记录新的修改
所有关于layer的修改都会保存在在mCurrentState中.
另外一个条件就是mCurrentState.handle != nullptr,当满足上述条件后就会做一些操作
首先判断所要等待的layer存在,如果存在就向它的mLocalSyncPoints添加一个SyncPonit,并向自己的mRemoteSyncPoints里添加一个SyncPoint,
然后添加setTransactionFlags(eTransactionNeeded)标志,代表layer发生了变化,方便执行事务的时候处理这个layer,之后无乱如何都会执行
到mPendingStates.push_back(mCurrentState);方法 将mCurrentState放到mPendingStates中去.
这里要说明下,调用pushPendingState()方法的地方只有两处
1 void Layer::deferTransactionUntil(const sp<IBinder>& handle,
uint64_t frameNumber) {
mCurrentState.handle = handle;
mCurrentState.frameNumber = frameNumber;
// We don't set eTransactionNeeded, because just receiving a deferral
// request without any other state updates shouldn't actually induce a delay
mCurrentState.modified = true;
pushPendingState();
mCurrentState.handle = nullptr;
mCurrentState.frameNumber = 0;
mCurrentState.modified = false;
}
设置mCurrentState.handle 的地方有这一处
这里执行完成pushPendingState()后就把frameNumber和handle设置成0了,所以第二个地方Layer::doTransaction(uint32_t flags)
如果有其他地方改变了layer属性,调用它的时候只会执行mPendingStates.push_back(mCurrentState).
还有一点值得注意的
auto syncPoint = std::make_shared<SyncPoint>(
mCurrentState.frameNumber);
if (handleLayer->addSyncPoint(syncPoint)) {
mRemoteSyncPoints.push_back(std::move(syncPoint));
这里创建了一个shared变量并且使用move语义进行push_back说明二者使用的是统一快内存,一个状态变了另一个也会变
另外SyncPoint里面设置的frameNumber就是mCurrentState的frameNumber,也就是说要等到hanlde所对应的窗口到达它的frameNumber时候才进行处理自己的事务(这也反映了如何使两个窗口同步)
这里我们重新看一下前面SurfaceFlinger::handleTransactionLocked函数里面的
currentLayers[i]->notifyAvailableFrames()
void Layer::notifyAvailableFrames() {
auto headFrameNumber = getHeadFrameNumber();
bool headFenceSignaled = headFenceHasSignaled();
Mutex::Autolock lock(mLocalSyncPointMutex);
for (auto& point : mLocalSyncPoints) {
if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
point->setFrameAvailable();
}
}
}
这个函数发现有其他layer在等待自己的某一帧,如果这一帧已经绘制完成则会使用setFrameAvailable()设置SyncPoint的mFrameIsAvailable变量为true,代表所等待的帧已经到来,注意这时对应的layer的mRemoteSyncPoints里面的SyncPoint的值也会发生变化,我们后边会看到对设置好mFrameIsAvailable的帧的处理.
这里我们重新回到函数uint32_t Layer::doTransaction(uint32_t flags) 分析applyPendingStates()函数
函数的代码如下
bool Layer::applyPendingStates(State* stateToCommit) {
bool stateUpdateAvailable = false;
while (!mPendingStates.empty()) {
if (mPendingStates[0].handle != nullptr) {
if (mRemoteSyncPoints.empty()) {
// If we don't have a sync point for this, apply it anyway. It
// will be visually wrong, but it should keep us from getting
// into too much trouble.
ALOGE("[%s] No local sync point found", mName.string());
popPendingState(stateToCommit);
stateUpdateAvailable = true;
continue;
}
if (mRemoteSyncPoints.front()->getFrameNumber() !=
mPendingStates[0].frameNumber) {
ALOGE("[%s] Unexpected sync point frame number found",
mName.string());
// Signal our end of the sync point and then dispose of it
mRemoteSyncPoints.front()->setTransactionApplied();
mRemoteSyncPoints.pop_front();
continue;
}
if (mRemoteSyncPoints.front()->frameIsAvailable()) {
// Apply the state update
popPendingState(stateToCommit);
stateUpdateAvailable = true;
// Signal our end of the sync point and then dispose of it
mRemoteSyncPoints.front()->setTransactionApplied();
mRemoteSyncPoints.pop_front();
} else {
break;
}
} else {
popPendingState(stateToCommit);
stateUpdateAvailable = true;
}
}
// If we still have pending updates, wake SurfaceFlinger back up and point
// it at this layer so we can process them
if (!mPendingStates.empty()) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
mCurrentState.modified = false;
return stateUpdateAvailable;
}
这个函数就是对mPendingStates进行处理生成新的CurrentState的过程,大致进行下如下分析:
首先通过一个while循环去处理所有的mPendingStates, 函数体内是我们主要关注的内容.
先从由旧到新获取State,然后判断是否等到了hanlde所对应的layer的帧是否出现,如果没有出现stateUpdateAvailable肯定为false 了,另外还有一种对错误情况的处理,就是mRemoteSyncPoints.front()->getFrameNumber() !=
mPendingStates[0].frameNumber)所对应的条件,读者不妨详细读一下,这种方式确实可以控制事务的处理.
还有mPendingStates[0].handle == nullptr的情况.这里还要注意一种情况,就是break所对应的语句处,这种情况一个事务也不能处理,有可能mPendingStates
还不是空的就跳出循环了,所以要对其进行检查,重新设置flags方便下回处理.最后返回stateUpdateAvailable,代表是否有新的状态需要处理.
回到uint32_t Layer::doTransaction(uint32_t flags)的代码中
如果有新的事务需要处理则就会进入下面的代码,首先获取layerStack的栈变量 这时多线程操作中常用的手段,然后判断size是否发生变化.如代码第9行.这里的requested代表客户端请求的帧大小. 如果requestsize 发生了变化,是要通知给生产者和消费者的,mSurfaceFlingerConsumer->setDefaultBufferSize(
c.requested.w, c.requested.h)这个函数最终设置给了BufferQueueCore的defaultWidth和Buffer,BufferQueueCore是生产者和消费者共用的数据.
34行的代码判断请求的大小是否与active的大小一致(active的大小是经过变换后的大小)
35到47行代码判断如果我们在固定大小的模式,并且不包含边带数据,即使大小发生的变化我们也不去处理这种变化,所以给flags 添加了eDontUpdateGeometryState位.
下面就是对调整大小的部分进行处理,也分为两种情况:
第一中情况 if (mFreezePositionUpdates) { 说明当前是冻结状态,所以大小是没有变化的,变化的只有位置,这种情况下希望马上应用位置和变换,所以直接设置tx,ty,然后设置active还是为原来的active,其实三个数据已经都设置上了,因为这时候request.w request.h是和active中相等的. tx,ty也是相等的这里重新设置一下只是为了更新变换的类型.
第二种清空就是fixedsize的情况,直接赋值request到active.
60行代码判断经过变换后的大小还位置如果和当前正在绘制的有变化,则设置flags |= Layer::eVisibleRegion,用于通知Surfaceflinger region有发生变化需要重绘.
如果sequence发生了变化说明内容也有变化,则要设置this->contentDirty = true,表明内容发生变化需要重新绘制,如果内容没有发生变化,就只是简单的裁剪就可以了.裁剪的部分我们单独用一片文章去分析.这里说明一下引起sequence变化的原因,主要是layer的alpha变化,裁剪部分变化,flags变化,z轴变化,layerStack,矩阵,位置变化都会引起sequence变化.
第73-76行如果layer变乘隐藏状态则需要通知等待与之同步的layer帧可用.
最后79行提交事务
void Layer::commitTransaction(const State& stateToCommit) {
mDrawingState = stateToCommit;
}
注意这个函数将mCurrentState的状态拷贝到了mDrawingState状态,其实在这个事务处理函数中mDrawingState的很多状态也发生的变化,但是它现在与mDrawingState的内容是一致的了.
现在layer的事务就处理完了,这里进行下总结,其实layer的事务中只处理了两件事情,1处理SyncPoint(同步点),主要是通过延迟事务处理完成 2 layer region变化的处理,主要就是requet到active的变化
回到void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)函数
if (transactionFlags & eTraversalNeeded) {
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
}
}
如果发现有layer发生变化了则设置mVisibleRegionsDirty=true,用于通知Surfaceflinger需要刷新下一帧.
后面的部分主要处理了display的变化,在多display管理一章中我们已经分析.这里就不重新分析了.所以直接跳到最后一部分代码
const LayerVector& layers(mDrawingState.layersSortedByZ);
if (currentLayers.size() > layers.size()) {
// layers have been added
mVisibleRegionsDirty = true;
}
// some layers might have been removed, so
// we need to update the regions they're exposing.
if (mLayersRemoved) {
mLayersRemoved = false;
mVisibleRegionsDirty = true;
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(layers[i]);
if (currentLayers.indexOf(layer) < 0) {
// this layer is not visible anymore
// TODO: we could traverse the tree from front to back and
// compute the actual visible region
// TODO: we could cache the transformed region
const Layer::State& s(layer->getDrawingState());
Region visibleReg = s.active.transform.transform(
Region(Rect(s.active.w, s.active.h)));
invalidateLayerStack(s.layerStack, visibleReg);
}
}
}
commitTransaction();
updateCursorAsync();
layer的数量发生变化肯定要重新绘制.
如果有layer被移除还要更新display的dirtyRegion,因为这里是最后一次处理被移除的layer的地方了.
最后提交事务
void SurfaceFlinger::commitTransaction()
{
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
recordBufferingStats(mLayersPendingRemoval[i]->getName().string(),
mLayersPendingRemoval[i]->getOccupancyHistory(true));
mLayersPendingRemoval[i]->onRemoved();
}
mLayersPendingRemoval.clear();
}
// If this transaction is part of a window animation then the next frame
// we composite should be considered an animation as well.
mAnimCompositionPending = mAnimTransactionPending;
mDrawingState = mCurrentState;
mTransactionPending = false;
mAnimTransactionPending = false;
mTransactionCV.broadcast();
}
提交事务中先处理要移除的layer,这个过程中做了一些状态的记录,用于dump信息,另外就是调用mLayersPendingRemoval[i]->onRemoved();发送remove的通知,最终会调用到ConsumerBase的abandonLocked方法,
该方法中先释放buffer,然后调用 mConsumer->consumerDisconnect()做一些清理工作
void ConsumerBase::abandonLocked() {
CB_LOGV("abandonLocked");
if (mAbandoned) {
CB_LOGE("abandonLocked: ConsumerBase is abandoned!");
return;
}
for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
freeBufferLocked(i);
}
// disconnect from the BufferQueue
mConsumer->consumerDisconnect();
mConsumer.clear();
}
回到void SurfaceFlinger::commitTransaction()中,除了要反转mDrawState和mCurrentState(注意layer和Surfaceflinger都要这个两个变量,layer中的主要处理一个window中的状态变换,而SurfaceFlinger代表全局的状态,其实主要就是Display状态变换),反转之后设置 mTransactionPending = false; 代表事物已经处理完成
mAnimTransactionPending = false; 动画事务处理完成
mTransactionCV.broadcast();发送广播唤醒等待事物处理的线程.
handleTransactionLocked函数的最后一项工作就是更新CursorLayer,cursorlayer也就是光标层
void SurfaceFlinger::updateCursorAsync()
{
HWComposer& hwc(getHwComposer());
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id < 0) {
continue;
}
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) {
if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) {
continue;
}
const sp<Layer>& layer(currentLayers[i]);
Rect cursorPos = layer->getPosition(hw);
hwc.setCursorPositionAsync(id, cursorPos);
break;
}
}
}
因为layer已经发生变化,要找到它新的位置通知HWC组件,因为这样可以让硬件特殊处理该曾,减少光标滞后的问题.
我们在来回顾一下对于SurfaceFlinger的整体事务做了什么:
1 确认是否有区域变脏
2 处理没一个layer的事务
3 处理display的变化
4 处理layer的增加减少
到此事务的处理我们就看完了,接下来在在 case MessageQueue::INVALIDATE:中处理的就是页面反转
refreshNeeded |= handleMessageInvalidate();
handleMessageInvalidate是处理页面反转的函数.
bool SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
return handlePageFlip(); }
bool SurfaceFlinger::handlePageFlip()
{
Region dirtyRegion;
bool visibleRegions = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);
bool frameQueued = false;
// 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;
for (size_t i = 0, count = layers.size(); i<count ; i++) {
const sp<Layer>& layer(layers[i]);
if (layer->hasQueuedFrame()) {
frameQueued = true;
if (layer->shouldPresentNow(mPrimaryDispSync)) {
layersWithQueuedFrames.push_back(layer.get());
} else {
layer->useEmptyDamage();
}
} else {
layer->useEmptyDamage();
}
}
for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
Layer* layer = layersWithQueuedFrames[i];
const Region dirty(layer->latchBuffer(visibleRegions));
layer->useSurfaceDamage();
const Layer::State& s(layer->getDrawingState());
invalidateLayerStack(s.layerStack, dirty);
}
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 && layersWithQueuedFrames.empty()) {
signalLayerUpdate();
}
// Only continue with the refresh if there is actually new work to do
return !layersWithQueuedFrames.empty();
}
函数代码不太多,但是里面函数嵌套很多.我们先总体看下函数做了什么.
14行到21行就是收集那些有可用帧的layer,判断有可用帧的条件有两层,第一层用15行layer->hasQueuedFrame()函数判断是否有buffer数据已经入队列
/*
* Returns if a frame is queued.
*/
bool hasQueuedFrame() const { return mQueuedFrames > 0 ||
mSidebandStreamChanged || mAutoRefresh; }
函数很简单,在同步模式下主要看mQueuedFrames,一部模式主要看mAutoRefresh,还有中特殊情况就是视频边带数据改变.
第二层判断就是 if (layer->shouldPresentNow(mPrimaryDispSync)) 这个条件,
bool Layer::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 =
mSurfaceFlingerConsumer->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;
}
函数也比较简单,就是判断落在下一个app vync时间之前的和落在下一个vsync(不包含偏移)一秒之后的帧都满足需求. 另外边带改变和mAutoRefresh也都满足.为什么1s以后的帧也要被收集呢,因为它是不合理的帧,要在这次刷新中处理掉.如果在收集过程中没有满足的帧则应该将layer的受损区域清空(受损区域是指数据发生变化的区域),因为还没有合适的buffer,所以也不用管那些帧.而我们锁定buffer之后就会从buffer中拿出来受损区域,重新赋值给layer.
接下来在页面反转的第二个for循环里面根据之前收集到的包含可用帧和无效帧的集合,对其中的没一个layer做处理,锁定buffer. 是页面反转最重要的一部分.
我们先不看锁定buffer的过程,先来分析下锁定之后的逻辑,第31到33行有新入队列的buffer却没有落在可以处理范围内的layer,这种情况说明很快layer就可以使用,所以要在下一个vsync的时候处理,发出signalLayerUpdate();用于接收下一个sf_vsync事件. 最后返回layersWithQueuedFrames是否不是空的(不为空说明有新的buffer被锁定了,所以要刷新显示)
现在我们回来看下latchBuffer的过程.函数比较长我们分成很多段来看.
Region Layer::latchBuffer(bool& recomputeVisibleRegions)
{
ATRACE_CALL();
if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
// mSidebandStreamChanged was true
mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
if (mSidebandStream != NULL) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
recomputeVisibleRegions = true;
const State& s(getDrawingState());
return s.active.transform.transform(Region(Rect(s.active.w, s.active.h)));
}
注意latchBuffer是对每一个layer处理的,首先如果边带数据改变则先处理边带变化,下一帧再处理其他变化,所以要先重新设置上事务,方便下一帧处理. 最后对边带数据变换,返回下一个buffer的边带region.返回前要经过变换处理,如何变换我们就不分析了,可以参考我的另一篇博客Surfaceflinger(3):变换.边带数据不是我们重点分析的对象,所以我们继续向下分析.
后面的所有逻辑都是在 if (mQueuedFrames > 0 || mAutoRefresh) 条件成立的情况下进行的,最后跳出该条件返回一个计算出的Dirty Region . 条件不难理解,之前说过收集要处理的buffer的时候要满足layer->hasQueuedFrame()条件,这个条件对应的情况有三个,其中第一个条件边带变化的情况已经处理完了,下面处理的就是后面的两种情况:包含QueuedFrames和mAutoRefresh的情况.
这段代码还是很长我们分段处理.其中开始部分是创建一个Reject对象,我们先跳过,用到的时候在去分析.
auto headFrameNumber = getHeadFrameNumber();
bool matchingFramesFound = false;
bool allTransactionsApplied = true;
{
Mutex::Autolock lock(mLocalSyncPointMutex);
for (auto& point : mLocalSyncPoints) {
if (point->getFrameNumber() > headFrameNumber) {
break;
}
matchingFramesFound = true;
if (!point->frameIsAvailable()) {
// We haven't notified the remote layer that the frame for
// this point is available yet. Notify it now, and then
// abort this attempt to latch.
point->setFrameAvailable();
allTransactionsApplied = false;
break;
}
allTransactionsApplied &= point->transactionIsApplied();
}
}
if (matchingFramesFound && !allTransactionsApplied) {
mFlinger->signalLayerUpdate();
return outDirtyRegion;
}
首先是对SyncPoint的处理,我们之前分析过,用于同步的两个数据结构mLocalSyncPoints和mRemoteSyncPoints. mRemoteSyncPoints中存放的是表示正在等别的layer的帧的帧,而mLocalSyncPoints中存放的是用于通知帧已经到达的帧.这里如果queueBuffer的地一个buffer所代表的帧已经超过了mLocalSyncPoints要等待的帧,如果还没有通知mRemoteSyncPoints中对应的帧可用,我们就需要通知对应的mRemoteSyncPoints中的帧可用了.通过point->setFrameAvailable()方法去通知,我们前面也分析了该方法. 最后根据两种不同的情况去设置allTransactionsApplied变量.最后如果找到了可用的LocalSyncPoints,但是不是所有的LocalSyncPoints都变为可用,就要等待所有的LocalSyncPoints都可用后再去刷新这个layer,直接请求下一个sf_vync,然后返回.为什么要这么做呢? 因为要连个layer一起绘制同一个framenumber. 这里有可能拥有对应RemoteSyncPoint 的layer已经被遍历完成.
下面就进入了最为关键的一步,真正的锁定buffer(acquireBuffer)
// This boolean is used to make sure that SurfaceFlinger's shadow copy
// of the buffer queue isn't modified when the buffer queue is returning
// BufferItem's that weren't actually queued. This can happen in shared
// buffer mode.
bool queuedBuffer = false;
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
mLastFrameNumberReceived);
这个函数层层包装,我们自定向下进行分析.读者一定要留神每个段落分析的是哪个函数的哪部分,一定要对照代码去看下面的段落
status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer,
uint64_t maxFrameNumber)
{
ATRACE_CALL();
ALOGV("updateTexImage");
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
ALOGE("updateTexImage: GLConsumer is abandoned!");
return NO_INIT;
}
// Make sure the EGL state is the same as in previous calls.
status_t err = checkAndUpdateEglStateLocked();
if (err != NO_ERROR) {
return err;
}
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.
err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
maxFrameNumber);
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 slot = item.mSlot;
if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR);
return BUFFER_REJECTED;
}
if (autoRefresh) {
*autoRefresh = item.mAutoRefresh;
}
if (queuedBuffer) {
*queuedBuffer = item.mQueuedBuffer;
}
// Release the previous buffer.
#ifdef USE_HWC2
err = updateAndReleaseLocked(item, &mPendingRelease);
#else
err = updateAndReleaseLocked(item);
#endif
if (err != NO_ERROR) {
return err;
}
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.
err = bindTextureImageLocked();
}
return err;
}
函数7-9行检查该layer是否已经被废弃.11行检查EGL状态.
函数18行是这个函数最关键的一部分,后面部分都是对该函数的返回结果做检查,我们先不分析后面的部分,跳入18行的函数进行分析,回来之后再分析这个函数的后半部分.
status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
nsecs_t presentWhen, uint64_t maxFrameNumber) {
status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
maxFrameNumber);
if (result == NO_ERROR) {
mTransformToDisplayInverse = item->mTransformToDisplayInverse;
mSurfaceDamage = item->mSurfaceDamage;
}
return result;
}
首先说明下这个函数的三个参数,BufferItem* item传出参数,用于传出锁定的buffer,nsecs_t presentWhen下一个vsync的时间,maxFrameNumber最后收到的一个queueBuffer. 最后如果返回没有发生错误,设置layer的mTransformToDisplayInverse变量和mSurfaceDamage变量,mSurfaceDamage我们前面看到过,前面收集要处理的buffer的时候会把SurfaceDamage清除掉,这里设置了新的SurfaceDamage.
接着往里面追
status_t GLConsumer::acquireBufferLocked(BufferItem *item,
nsecs_t presentWhen, uint64_t maxFrameNumber) {
status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen,
maxFrameNumber);
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).
if (item->mGraphicBuffer != NULL) {
int slot = item->mSlot;
mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
}
return NO_ERROR;
}
这汗函数有嵌套了一层acquireBufferLocked函数,在调用ConsumerBase::acquireBufferLocked返后如果发生了错误直接返回,如果没有发生操作就用获取的新的buffer创建一个EglImage,这个EglImage是用于快速的纹理拷贝,是GLES的扩展请参考https://software.intel.com/en-us/articles/using-opengl-es-to-accelerate-apps-with-legacy-2d-guis 链接文章.好了,接下来就可以进入有一个正题
status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
nsecs_t presentWhen, uint64_t maxFrameNumber) {
if (mAbandoned) {
CB_LOGE("acquireBufferLocked: ConsumerBase is abandoned!");
return NO_INIT;
}
status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
if (err != NO_ERROR) {
return err;
}
if (item->mGraphicBuffer != NULL) {
mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
}
mSlots[item->mSlot].mFrameNumber = item->mFrameNumber;
mSlots[item->mSlot].mFence = item->mFence;
CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64,
item->mSlot, item->mFrameNumber);
return OK;
}
这里又嵌套了一层acquireBuffer,不要灰心,这个就是最后一个了,首先就是对layer状态的检查,之后mConsumer->acquireBuffer函数获取buffer,返回之后给自己的槽赋值,这样绘制的时候就可以使用ConsumerBase中的槽获取数据,就可以释放BufferQueueCore中的槽了(或许已经释放了),废话不多说,直接进入下一个acquireBuffer.
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
ATRACE_CALL();
int numDroppedBuffers = 0;
sp<IProducerListener> listener;
{
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.
int numAcquiredBuffers = 0;
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isAcquired()) {
++numAcquiredBuffers;
}
}
if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
return INVALID_OPERATION;
}
bool sharedBufferAvailable = mCore->mSharedBufferMode &&
mCore->mAutoRefresh && mCore->mSharedBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT;
// 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() && !sharedBufferAvailable) {
return NO_BUFFER_AVAILABLE;
}
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.
// Skip this if we're in shared buffer mode and the queue is empty,
// since in that case we'll just return the shared buffer.
if (expectedPresent != 0 && !mCore->mQueue.empty()) {
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.
//
// 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).
//
// 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.
while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
const BufferItem& bufferItem(mCore->mQueue[1]);
// If dropping entry[0] would leave us with a buffer that the
// consumer is not yet ready for, don't drop it.
if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
break;
}
// 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.
//
// We may want to add an additional criterion: don't drop the
// earlier buffer if entry[1]'s fence hasn't signaled yet.
nsecs_t desiredPresent = bufferItem.mTimestamp;
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());
if (!front->mIsStale) {
// Front buffer is still in mSlots, so mark the slot as free
mSlots[front->mSlot].mBufferState.freeQueued();
// After leaving shared buffer mode, the shared buffer will
// still be around. Mark it as no longer shared if this
// operation causes it to be free.
if (!mCore->mSharedBufferMode &&
mSlots[front->mSlot].mBufferState.isFree()) {
mSlots[front->mSlot].mBufferState.mShared = false;
}
// Don't put the shared buffer on the free list
if (!mSlots[front->mSlot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(front->mSlot);
mCore->mFreeBuffers.push_back(front->mSlot);
}
listener = mCore->mConnectedProducerListener;
++numDroppedBuffers;
}
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
}
// See if the front buffer is ready to be acquired
nsecs_t desiredPresent = front->mTimestamp;
bool bufferIsDue = desiredPresent <= expectedPresent ||
desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
bool consumerIsReady = maxFrameNumber > 0 ?
front->mFrameNumber <= maxFrameNumber : true;
if (!bufferIsDue || !consumerIsReady) {
BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
" (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64
" consumer=%" PRIu64,
desiredPresent, expectedPresent,
desiredPresent - expectedPresent,
systemTime(CLOCK_MONOTONIC),
front->mFrameNumber, maxFrameNumber);
return PRESENT_LATER;
}
BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
"(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
desiredPresent - expectedPresent,
systemTime(CLOCK_MONOTONIC));
}
int slot = BufferQueueCore::INVALID_BUFFER_SLOT;
if (sharedBufferAvailable && mCore->mQueue.empty()) {
// make sure the buffer has finished allocating before acquiring it
mCore->waitWhileAllocatingLocked();
slot = mCore->mSharedBufferSlot;
// Recreate the BufferItem for the shared buffer from the data that
// was cached when it was last queued.
outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer;
outBuffer->mFence = Fence::NO_FENCE;
outBuffer->mCrop = mCore->mSharedBufferCache.crop;
outBuffer->mTransform = mCore->mSharedBufferCache.transform &
~static_cast<uint32_t>(
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
outBuffer->mScalingMode = mCore->mSharedBufferCache.scalingMode;
outBuffer->mDataSpace = mCore->mSharedBufferCache.dataspace;
outBuffer->mFrameNumber = mCore->mFrameCounter;
outBuffer->mSlot = slot;
outBuffer->mAcquireCalled = mSlots[slot].mAcquireCalled;
outBuffer->mTransformToDisplayInverse =
(mCore->mSharedBufferCache.transform &
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
outBuffer->mSurfaceDamage = Region::INVALID_REGION;
outBuffer->mQueuedBuffer = false;
outBuffer->mIsStale = false;
outBuffer->mAutoRefresh = mCore->mSharedBufferMode &&
mCore->mAutoRefresh;
} else {
slot = front->mSlot;
*outBuffer = *front;
}
ATRACE_BUFFER_INDEX(slot);
BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
slot, outBuffer->mFrameNumber, outBuffer->mGraphicBuffer->handle);
if (!outBuffer->mIsStale) {
mSlots[slot].mAcquireCalled = true;
// Don't decrease the queue count if the BufferItem wasn't
// previously in the queue. This happens in shared buffer mode when
// the queue is empty and the BufferItem is created above.
if (mCore->mQueue.empty()) {
mSlots[slot].mBufferState.acquireNotInQueue();
} else {
mSlots[slot].mBufferState.acquire();
}
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
if (outBuffer->mAcquireCalled) {
outBuffer->mGraphicBuffer = NULL;
}
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.
mCore->mDequeueCondition.broadcast();
ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
VALIDATE_CONSISTENCY();
}
if (listener != NULL) {
for (int i = 0; i < numDroppedBuffers; ++i) {
listener->onBufferReleased();
}
}
return NO_ERROR;
}
函数不算长,大部分都是注释和log.
10-17行检查获得的buffer数量是否大于最大数量,如果超出则返回INVALID_OPERATION
18-24行检查如果不是sharedBufferAvailable模式(同步模式)这种情况要从mQueue里面获取buffer,如果mQueue里没有buffer则返回 NO_BUFFER_AVAILABLE
37-103行所处理的情况是如果指定了下一帧预期的时间,并且mQueue中包含一些buffer,则可能要根据预期的时间丢弃一些没有用的帧,我们来分析这部分. 45-86行 判断如果时间不是自动生成的并且包含多个buffer,就要选择性的丢弃一些帧,48行判断maxFrameNumber的作用是防止不要把所有的帧都丢掉.57-66行可以看出,后面要进行丢处理的帧范围必须在预期的时间一秒内.70行判断是一个有效的buffer才被处理,在满足147行的buffer都是无效的buffer,需要被释放,所以这段代码块就是用于释放buffer,代码很简单就不解释了.85-86则换下一个buffer进行处理.跳出while循环的89-99行代码判断如果没有可以处理的帧则返回PRESENT_LATER(因为已经有buffer如队列,却不能处理所以要后面才能处理),返回PRESENT_LATER意味着要关心下一个sf_vsync事件.
函数进入到105行后则说明已经选好了可用的buffer.
105-124行 是对sharedBuffer模式的处理,把sharedbuffer属性赋值给outBuffer输出.
125-126则是同步模式的赋值
131-139行 通过acquire函数增加槽的计数 并设置mFence=NO_FENCE
142-159行做的是最后的清理工作,并且通知生产者有新的槽可用
到这里最里曾的acquireBuffer就看完了,从这里看返回值就4种,分别是INVALID_OPERATION, NO_BUFFER_AVAILABLE,PRESENT_LATER,NO_ERROR,后面我们会关注返回值的处理.
回到status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer,uint64_t maxFrameNumber)函数
19-26行 对出出错的返回 将NO_BUFFER_AVAILABLE变成NO_ERROR直接返回.其余的返回上一层函数返回的错误码
29-30行 使用reject判断是否要拒绝这个buffer,到这里我们就可以分析Reject类的实现了
struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
Layer::State& front;
Layer::State& current;
bool& recomputeVisibleRegions;
bool stickyTransformSet;
const char* name;
int32_t overrideScalingMode;
bool& freezePositionUpdates;
Reject(Layer::State& front, Layer::State& current,
bool& recomputeVisibleRegions, bool stickySet,
const char* name,
int32_t overrideScalingMode,
bool& freezePositionUpdates)
: front(front), current(current),
recomputeVisibleRegions(recomputeVisibleRegions),
stickyTransformSet(stickySet),
name(name),
overrideScalingMode(overrideScalingMode),
freezePositionUpdates(freezePositionUpdates) {
}
virtual bool reject(const sp<GraphicBuffer>& buf,
const 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)
if (item.mTransform & Transform::ROT_90) {
swap(bufWidth, bufHeight);
}
int actualScalingMode = overrideScalingMode >= 0 ?
overrideScalingMode : item.mScalingMode;
bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
if (front.active != front.requested) {
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
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.active = front.active;
current.modified = true;
// recompute visible region
recomputeVisibleRegions = true;
}
ALOGD_IF(DEBUG_RESIZE,
"[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
" drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} }}\n",
name,
bufWidth, bufHeight, item.mTransform, item.mScalingMode,
front.active.w, front.active.h,
front.crop.left,
front.crop.top,
front.crop.right,
front.crop.bottom,
front.crop.getWidth(),
front.crop.getHeight(),
front.requested.w, front.requested.h);
}
if (!isFixedSize && !stickyTransformSet) {
if (front.active.w != bufWidth ||
front.active.h != bufHeight) {
// reject this buffer
ALOGE("[%s] rejecting buffer: "
"bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}",
name, 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.
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;
}
if (front.crop != front.requestedCrop) {
front.crop = front.requestedCrop;
current.crop = front.requestedCrop;
recomputeVisibleRegions = true;
}
freezePositionUpdates = false;
return false;
}
};
28-55行更新Layer->mDrawState和Layer->mCurrentState的active状态
57-63行 如果更新后的宽高和buffer不符合,说明这个buffer是一个无效的buffer,拒绝提交
67-76行 如果透明区域发生变化,更新透明区域,设置recomputeVisibleRegions = true 用于告诉Surfaceflinger重新计算可见区域
78-81行 更新裁剪區域
82行 冻结区域的位置已经更新完了 设置成false
所以reject函数只拒绝那些不符合大小的buffer,并且完成一些状态的切换
回到status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber)函数
被拒绝的buffer返回BUFFER_REJECTED
40-43行调用updateAndReleaseLocked方法,我们这里之分析hwc1的,后面会有文章总结1和2的区别
status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item,
PendingRelease* pendingRelease)
{
status_t err = NO_ERROR;
int slot = item.mSlot;
if (!mAttached) {
GLC_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL "
"ES context");
releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
mEglDisplay, EGL_NO_SYNC_KHR);
return INVALID_OPERATION;
}
// Confirm state.
err = checkAndUpdateEglStateLocked();
if (err != NO_ERROR) {
releaseBufferLocked(slot, mSlots[slot].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).
err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
if (err != NO_ERROR) {
GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
mEglDisplay, slot);
releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
mEglDisplay, EGL_NO_SYNC_KHR);
return UNKNOWN_ERROR;
}
// Do whatever sync ops we need to do before releasing the old slot.
if (slot != mCurrentTexture) {
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(slot, mSlots[slot].mGraphicBuffer,
mEglDisplay, EGL_NO_SYNC_KHR);
return err;
}
}
GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
mCurrentTexture, mCurrentTextureImage != NULL ?
mCurrentTextureImage->graphicBufferHandle() : 0,
slot, mSlots[slot].mGraphicBuffer->handle);
// Hang onto the pointer so that it isn't freed in the call to
// releaseBufferLocked() if we're in shared buffer mode and both buffers are
// the same.
sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
if (pendingRelease == nullptr) {
status_t status = releaseBufferLocked(
mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
if (status < NO_ERROR) {
GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
strerror(-status), status);
err = status;
// keep going, with error raised [?]
}
} else {
pendingRelease->currentTexture = mCurrentTexture;
pendingRelease->graphicBuffer =
mCurrentTextureImage->graphicBuffer();
pendingRelease->display = mEglDisplay;
pendingRelease->fence = mEglSlots[mCurrentTexture].mEglFence;
pendingRelease->isPending = true;
}
}
// Update the GLConsumer state.
mCurrentTexture = slot;
mCurrentTextureImage = nextTextureImage;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
mCurrentTimestamp = item.mTimestamp;
mCurrentFence = item.mFence;
mCurrentFrameNumber = item.mFrameNumber;
computeCurrentTransformMatrixLocked();
return err;
}
5-16行检查gles状态
20 行在对应的槽上创建了一个EGLImageKHR用于纹理拷贝和当作纹理数据(注意这里可能有耗时的操作)就是如果当前槽的EGLImageKHR还没有处理完成要等待GPU渲染完成(eglTerminate(mEglDisplay)函数),这种情况应该出现在不了.因为新的buffer会创建信息的EGLImage,创建失败要releaseBuffer.返回UNKNOWN_ERROR,这里还有些fence的处理我们就不分析了,等到专门分析fence的文章在去分析,最后面绑定如下数据
mCurrentTexture = slot;
mCurrentTextureImage = nextTextureImage;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
mCurrentTimestamp = item.mTimestamp;
mCurrentFence = item.mFence;
mCurrentFrameNumber = item.mFrameNumber;
回到status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber)函数
最后一部分对于老的设备,绑定纹理
最后总结下updateTexImage可能返回的错误类型
NVALID_OPERATION,NO_INIT, PRESENT_LATER,NO_ERROR ,NO_ERROR,BUFFER_REJECTED,UNKNOWN_ERROR
到这里就处理完成了updateTexImage函数,我们回到函数Region Layer::latchBuffer(bool& recomputeVisibleRegions)
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.
mFlinger->signalLayerUpdate();
return outDirtyRegion;
} else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
// If the buffer has been rejected, remove it from the shadow queue
// and return early
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.removeAt(0);
android_atomic_dec(&mQueuedFrames);
}
return outDirtyRegion;
} else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
// This can occur if something goes wrong when trying to create the
// EGLImage for this buffer. If this happens, the buffer has already
// been released, so we need to clean up the queue and bug out
// early.
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.clear();
android_atomic_and(0, &mQueuedFrames);
}
// Once we have hit this state, the shadow queue may no longer
// correctly reflect the incoming BufferQueue's contents, so even if
// updateTexImage starts working, the only safe course of action is
// to continue to ignore updates.
mUpdateTexImageFailed = true;
return outDirtyRegion;
}
这一段都是对错误的处理,分为三种情况
1updateResult == BufferQueue::PRESENT_LATER 这种情况说明有入队列的buffer但是处理它的时机还没到,所以重新发起sf_vsync请求
2 updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED,buffer的大小不符合,从mQueueItems移除
注意前面acquire的时候只是从BufferQueueCore中移除该layer,并没有从Layer的mQueueItems中移除,这里才进行移除,这里注意并没有清理BufferQueueCore中的槽
3 (updateResult != NO_ERROR || mUpdateTexImageFailed) 其他错误也是清楚mQueueItems中的槽,然后设置mUpdateTexImageFailed用于忽略这个layer的下一个更新.
注意上面三步都没有清理BufferQueueCore中的槽
处理完成错误情况接下来往下看
if (queuedBuffer) {
// Autolock scope
auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
Mutex::Autolock lock(mQueueItemLock);
// Remove any stale buffers that have been dropped during
// updateTexImage
while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
mQueueItems.removeAt(0);
android_atomic_dec(&mQueuedFrames);
}
mQueueItems.removeAt(0);
}
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
|| mAutoRefresh) {
mFlinger->signalLayerUpdate();
}
移除mQueueItems中无用的槽和要绘制的槽,如果最后还有没处理的槽就需要请求下一个sf_vsync处理了
if (updateResult != NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
return outDirtyRegion;
}
// update the active buffer
mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
if (mActiveBuffer == NULL) {
// this can only happen if the very first buffer was rejected.
return outDirtyRegion;
}
mRefreshPending = true;
mFrameLatencyNeeded = true;
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))
{
mCurrentCrop = crop;
mCurrentTransform = transform;
mCurrentScalingMode = scalingMode;
recomputeVisibleRegions = true;
}
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;
}
后面这段也比较简单,就是根据一些状态变化设置recomputeVisibleRegions(包括buffer变换和裁剪数据透明度变化,主要就是从Consumer到layer拿数据, 就不分析了
最后还有段对同步点的处理,主要就是清除可用的帧的同步点
// Remove any sync points corresponding to the buffer which was just
// latched
{
Mutex::Autolock lock(mLocalSyncPointMutex);
auto point = mLocalSyncPoints.begin();
while (point != mLocalSyncPoints.end()) {
if (!(*point)->frameIsAvailable() ||
!(*point)->transactionIsApplied()) {
// This sync point must have been added since we started
// latching. Don't drop it yet.
++point;
continue;
}
if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
point = mLocalSyncPoints.erase(point);
} else {
++point;
}
}
}
Region dirtyRegion(Rect(s.active.w, s.active.h));
// transform the dirty region to window-manager space
outDirtyRegion = (s.active.transform.transform(dirtyRegion));
最后返回变换后的dirtyRegion .
回到bool SurfaceFlinger::handlePageFlip()函数的分析
25行 拷贝消费者的surfaceDamageRegion(其实来在BufferItem)到layer中
26行 根据latchBuffer返回的Region更新每个Display的distyRegion
到这里页面翻转也分完成了
最后在onMessageReceived中判断是否有必要重绘数据决定是否要用signalRefresh发出请求
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
// repaint
signalRefresh();
}
break;
}
case MessageQueue::REFRESH: {
handleMessageRefresh();
break;
}
}
历尽千辛万苦,终于分析完成了INVALIDATE的流程. 下周分析refersh的流程