Layer收到onFrameAvaliable通知后,会通知SurfaceFlinger更新,重新进行图像合成
在SurfaceFlinger重新合成图像的过程中,会遍历所有发生变化的Layer,此时调用Layer的latchBuffer函数去BufferQueue中拿方才生产者入队的Buffer进行处理
Layer.latchBuffer
Region Layer::latchBuffer(bool& recomputeVisibleRegions)
{
ATRACE_CALL();
//如果mSidebandStreamChanged为true, 设置flag为eTransactionNeeded, recomputeVisibleRegions为true
//然后直接返回
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)));
}
//如果Layer中有待处理的BufferItem
Region outDirtyRegion;
if (mQueuedFrames > 0 || mAutoRefresh) {
// 如果已经调用了 updateTexImage() 方法,但是还没有执行图形合成,则跳过这个Layer,直接返回
if (mRefreshPending) {
return outDirtyRegion;
}
//获取旧的Buffer的状态
const State& s(getDrawingState());
const bool oldOpacity = isOpaque(s);
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
//初始化Reject对象,用于判断当前Buffer是否会被拒绝
Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0, mName.string(),
mOverrideScalingMode);
......
//调用updateTextureImage,将Buffer内容更新到Layer对应的纹理中。
bool queuedBuffer = false;
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
mLastFrameNumberReceived);
if (updateResult == BufferQueue::PRESENT_LATER) {
// 生产者如果不希望Buffer立刻显示,则通知SurfaceFLinger 下次Vsync到来时再进行更新,然后直接返回。
mFlinger->signalLayerUpdate();
return outDirtyRegion;
} else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
// 如果Buffer被拒绝,则从Layer队列移除,mQueueFrame计数 -1,然后直接返回
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.removeAt(0);
android_atomic_dec(&mQueuedFrames);
}
return outDirtyRegion;
} else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
// 当尝试创建EGLImage的时候失败, 表明对应的GraphicBuffer已经被释放掉了,需要情况Layer中的mQueueItem列表,将
// 计数重置为0, 然后直接返回
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.clear();
android_atomic_and(0, &mQueuedFrames);
}
mUpdateTexImageFailed = true;
return outDirtyRegion;
}
if (queuedBuffer) {
// Autolock scope
auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
Mutex::Autolock lock(mQueueItemLock);
// 丢弃过时的Buffer缓冲区
while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
mQueueItems.removeAt(0);
android_atomic_dec(&mQueuedFrames);
}
mQueueItems.removeAt(0);
}
// 如果处理玩完当前的Buffer后,Layer队列中仍然还要待处理的Buffer,则通知SurfaceFLinger 下次Vsync到来时再进行更新
if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
|| mAutoRefresh) {
mFlinger->signalLayerUpdate();
}
if (updateResult != NO_ERROR) {
// update发生错误,直接返回
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) {
// 第一次接收的Buffer,需要计算VisibleRegion
recomputeVisibleRegions = true;
}
//和旧的Buffer相比如果发生了变化,这将recomputeVisibleRegions设置为true, 表明需要重新计算Layer的Region
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;
mFreezePositionUpdates = false;
}
}
mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
if (oldOpacity != isOpaque(s)) {
recomputeVisibleRegions = true;
}
//记录这个Buffer的FrameNumber计数
mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
//记录下发生变化的区域,并返回给调用者
Region dirtyRegion(Rect(s.active.w, s.active.h));
// transform the dirty region to window-manager space
outDirtyRegion = (s.active.transform.transform(dirtyRegion));
}
return outDirtyRegion;
}
latchBuffer比较长, 主要作用分析是否需要重新计算当前Layer的visibleRegion
- 1:判断SidebandStream是否发生变换,如果发生变化则需要更新真个Layer
- 2:调用updateTextureImage函数来更新Buffer, 在这个函数中会调用acquireBuffer从BufferQueue队列中获取Buffer,参数为Rejector,顾名思义,这个在updateTextureImage函数中用来判断是否拒绝这个Buffer的
这个函数返回值分为以几种:
PRESENT_LATER:生产者如果不希望Buffer立刻显示,则通知SurfaceFLinger 下次Vsync到来时再进行更新
BUFFER_REJECTED:如果Buffer被拒绝,则从Layer队列移除,mQueueFrame计数 -1
UPDATE_FAILED:当尝试创建EGLImage的时候失败, 表明对应的GraphicBuffer已经被释放掉了,需要情况Layer中的mQueueItem列表,将计数重置为0, 然后直接返回 - 3:丢弃队列中所有过时的Buffer
- 4:如果处理玩完当前的Buffer后,Layer队列中仍然还要待处理的Buffer,则通知SurfaceFLinger 下次Vsync到来时再进行更新
- 5:和旧的Buffer相比如果发生了变化,这将recomputeVisibleRegions设置为true, 表明需要重新计算Layer的Region
- 6:记录下发生变化的区域,返回给调用者
接着看下updateTextureImage方法
status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer,
uint64_t maxFrameNumber)
{
......
// 检查EGL的状态,确保和上一次的EGL状态相同
status_t err = checkAndUpdateEglStateLocked();
BufferItem item;
// 从Buffer队列中获取下一个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;
}
//调用参数传入的Reject对象,判断Buffer是否符合我们的条件
int slot = item.mSlot;
if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR);
return BUFFER_REJECTED;
}
//更新Buffer,并且释放上一个Buffer
err = updateAndReleaseLocked(item);
return err;
}
updateTextureImage函数主要包含个流程
1:acquireBufferLocked从BufferQueue中获取Buffer,拿到Buffer后,将Buffer保存在mSlots[item->mSlot].mGraphicBuffer中。
2:调用参数传入的Rejecter对象。来判断图像缓冲区Buffer是否符合条件。
3:调用updateAndReleaseLocked函数更新Buffer,并且释放掉上一个Buffer
SurfaceFlingerConsumer.acquireBufferLocked
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;
}
SurfaceFlingerConsumer的acquireBufferLocked直接调用了父类的acquireBufferLocked函数。
status_t GLConsumer::acquireBufferLocked(BufferItem *item,
nsecs_t presentWhen, uint64_t maxFrameNumber) {
//调用父类ConsumerBase的acquireBufferLocked函数获取新的Buffer
status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen,
maxFrameNumber);
//然后根据获取的新GraphicBuffer创建一个EglImage,保存在GLConsumer的数组mEglSlots中
if (item->mGraphicBuffer != NULL) {
int slot = item->mSlot;
mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
}
return NO_ERROR;
}
GLConsumer的acquireBufferLocked函数也比较简单,调用父类ConsumerBase的acquireBufferLocked函数获取新的Buffer,然后根据获取的新GraphicBuffer创建一个EglImage,保存在GLConsumer的数组mEglSlots中。
GLConsumer维护了一个数组mEglSlots,和前面讲的mSlots类似,将EglImage对象保存在数组对应的slot位置上
同理GLConsumer的acquireBufferLocked也是直接调用BufferQueueConsumer的方法。
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);
//统计Consumer acquire buffer的数量,以及是否超过最大acquire的限制
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;
}
BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
// 如果Buffer被生产者指定了显示的时间,不到显示时间的Buffer不会被获取
// 如果指定了显示时间,但是在这帧画面前还有Buffer等待显示,此时可能会丢掉部分Buffer
if (expectedPresent != 0 && !mCore->mQueue.empty()) {
const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
//如果队列中待显示的Buffer大于1个,且第一个要显示的是指定时间的Buffer
while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
//去队列中的第二个Buffer
const BufferItem& bufferItem(mCore->mQueue[1]);
//如果第二个已经超过预期显示时间1S(已经太迟,来不及显示了)或者,还没有到显示时间,则不需要获取Buffer
nsecs_t desiredPresent = bufferItem.mTimestamp;
if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
desiredPresent > expectedPresent) {
break;
}
//否则立刻获取第二个Buffer,准备显示第二个Buffer,第一个Buffer丢掉
if (!front->mIsStale) {
// 将第一个Buffer值为FREE状态
mSlots[front->mSlot].mBufferState.freeQueued();
......
listener = mCore->mConnectedProducerListener;
++numDroppedBuffers;
}
//从队列中移除第一个Buffer,再次循化查找
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
}
// 如果拿到的Buffer 在下一个Vsync到来时还未到显示时间,且预期显示时间小于下一次Vsync + 1S 的时间,说明还未显示但是即将要显示,返回 PRESENT_LANTER
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) {
return PRESENT_LATER;
}
}
//查找到指定的Buffer,保存到出参outBuffer中
int slot = BufferQueueCore::INVALID_BUFFER_SLOT;
if (sharedBufferAvailable && mCore->mQueue.empty()) {
......
//shareBuffer的逻辑暂时不管
} else {
slot = front->mSlot;
*outBuffer = *front;
}
if (!outBuffer->mIsStale) {
//设置mAcquireCalled变量为true
mSlots[slot].mAcquireCalled = true;
if (mCore->mQueue.empty()) {
mSlots[slot].mBufferState.acquireNotInQueue();
} else {
//设置对应BufferState的状态为ACQUIRED状态
mSlots[slot].mBufferState.acquire();
}
mSlots[slot].mFence = Fence::NO_FENCE;
}
// 如果buffer已经被acquire过了,则把graphicBuffer的指针置为NULL,防止重复内存映射
if (outBuffer->mAcquireCalled) {
outBuffer->mGraphicBuffer = NULL;
}
//将Buffer从BufferQueue的mQueue队列中移除
mCore->mQueue.erase(front);
......
}
//如果有直接丢弃的Buffer,需要通知有Buffer释放
if (listener != NULL) {
for (int i = 0; i < numDroppedBuffers; ++i) {
listener->onBufferReleased();
}
}
return NO_ERROR;
}
BufferQueueConsumer的acquiredBuffer函数从BufferQueue中拿准备好的Buffer数据。
1:先统计消费者acquire的buffer的数量是否查过最大限度,超过的话则禁止获取
2:遍历mQueue队列,获取合适的Buffer。如果Queue中等待显示的Buffer数量大于1,需要查看队列后边是否有指定显示时间且显示时间已经到的Buffer,有到话则直接放弃前边一个,显示后一个。循环处理,直到找到最紧急显示到Buffer。
3:根据找到的Buffer判断该Buffer是有需要立刻显示,如果离指定显示时间大于一定时间,则发挥PRESENT_LATER,此次显示不再处理该Buffer。
4:拿到需要显示的Buffer,设置需要显示Buffer的状态为ACQUIRED,并且将它从mQueue等待对了移除。
5:如果有遗弃的Buffer,需要同时有Buffer释放。
分析到这里Buffer已经从BufferQueue队列获取到了,下一步看如何更新Buffer。
SurfaceFlinger.updateAndReleaseLocked
status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item,
PendingRelease* pendingRelease)
{
status_t err = NO_ERROR;
//获取要更新的GraphicBuffer slot值
int slot = item.mSlot;
//判断当前Consumer对应的纹理贴图是否已经Attch到当前的EGLContext上了
//创建Layer的时候,会为每个Layer创建了一个纹理。同时创建了SurfaceFlingerConsumer,将纹理的ID传给了Consumer.此时,纹理默认是attach到EGL context上的。
//如果EGL没有Context,则直接释放掉当前Buffer。不做更新处理
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;
}
// 检查EGL状态和上次相比是否发生了变化?
err = checkAndUpdateEglStateLocked();
if (err != NO_ERROR) {
releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
mEglDisplay, EGL_NO_SYNC_KHR);
return err;
}
// 为每个slot中的GraphicBuffer创建一个EGLImage,保存在GLConsumer的mEglSlots数组中。
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;
}
// 如果新获取GraphicBuffer和旧的graphicBuffer发生了变化,需要释放掉旧的graphicBuffer
if (slot != mCurrentTexture) {
err = syncForReleaseLocked(mEglDisplay);
if (err != NO_ERROR) {
// 旧的buffer无法释放,则释放掉新获取的GraphicBuffer
releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
mEglDisplay, EGL_NO_SYNC_KHR);
return err;
}
}
sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
// 释放掉旧的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 {
......
}
}
// 更新GLConsumer的状态,保存Buffer的内容.
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;
}
updateAndRelease方法从名称就可看出其操作内容。更新新Buffer,释放旧Buffer。
每一个Layer都和一个Surface对应, Surface在App端,是操作和填充当前窗口的接口,而Layer则在SurfaceFlinger端来描述这个窗口。Layer在创建的时候会创建一个纹理Texture,这个Texture id也保存在了SurfaceFlingerConsumer中。SurfaceFlinger绘制的时候遍历Layer,Layer又会调用自己的SurfaceFlingerConsumer将合适的Buffer更新到纹理中。
SufaceFlinger更新纹理,上一步介绍了如果从BufferQueue中获取Buffer.这一步介绍,如何更新到纹理。
1:首先做判断,是否attach到EGLContext,没有Attach则直接释放当前Buffer。普通Layer默认是Attach到SurfaceFlinger主线程的EGLContext上的。(需要attach的SurfaceView)
2:检查EGL状态和上次是否发生了变化
3:每个slot中的GraphicBuffer都会创建一个EGLImage,保存在GLConsumer的mEglSlots数组中。
4:释放掉旧的buffer
5:保存新的Buffer信息到GLConsumer信息中,等待将Buffer数据填充到openGL纹理中
上面的步骤已经把Buffer从Buffer队列获取到了,也已经将Buffer更新到GLConsumer中,同时也释放掉了旧的Buffer,但是何时填充纹理进行绘制呢?
也是在SurfaceFlinger进行图形合成的过程中,先执行了latchBuffer来更新纹理,后边后依次执行Layer的onDraw方法,进行绘制,Layer的onDraw方法会调用SurfaceFlingerConsumer的bindTextureImage来绑定并填充纹理。
status_t GLConsumer::bindTextureImageLocked() {
//检查mEglDisplay的状态
if (mEglDisplay == EGL_NO_DISPLAY) {
ALOGE("bindTextureImage: invalid display");
return INVALID_OPERATION;
}
//检测openGL是否有错误
GLenum error;
while ((error = glGetError()) != GL_NO_ERROR) {
GLC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
}
//绑定当前Layer的纹理信息
glBindTexture(mTexTarget, mTexName);
if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
mCurrentTextureImage == NULL) {
GLC_LOGE("bindTextureImage: no currently-bound texture");
return NO_INIT;
}
status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
mCurrentCrop);
if (err != NO_ERROR) {
GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
mEglDisplay, mCurrentTexture);
return UNKNOWN_ERROR;
}
//将Buffer内容填充到纹理
mCurrentTextureImage->bindToTextureTarget(mTexTarget);
......
}
这个步骤将纹理绑定到了EGLContext, 然后调用了glEGLImageTargetTexture2DOES(texTarget,static_cast<GLeglImageOES>(mEglImage));将Buffer内容填充到了纹理中。这样纹理也准备好了,就等SurfaceFlinger进行合成了。
总结:
一个GraphicBuffer缓冲区如何从Producer传递到Consumer,以及Consumer接收到之后如何处理已经分析完成了。过程比较长,做一下简单的总结。
- 步骤1: 生产者想要绘制图像,必须要有一个GraphicBuffer图像缓冲区,所以必须先调用生产者的dequeueBuffer,从Buffer队列获取一个可用的Buffer。
获取的时候优先从Buffer队列的FreeBuffer队列查找空闲slot,如果找不到则从FreeSlot队列查找,然后为该Slot分配一个缓冲区。如果Buffer属性发生变化则需要重新分配,Surface中保存的GraphicBuffer也需要释放掉重新从Buffer队列中requestBuffer。 - 步骤2:生产者绘制完图像后,需要把完成的Buffer放入Buffer队列的mQueue中,等待消费者处理后进行显示。
在将Buffer放入mQueue的时候,如果队列中最后一个有未来得及处理的Buffer且该Buffer可以被放弃,则直接替换,否则将Buffer放入队列末尾。 - 步骤3:生产者将Buffer放入队列之后会调用onFrameAvaliable通知消费者SufaceFlingerConsumer,SufaceFlingerConsumer又会通知Layer,Layer会将Buffer信息保存到自己的列表中。然后通知SurfaceFlinger进行更新。
- 步骤4:SurfaceFlinger更新步骤会遍历mLayerSortByZ列表,依次处理所有的Layer,此时会调用Layer的latchBuffer来更新Layer对应的纹理。
更新Layer纹理,首先调用acquireBuffer从Buffer队列获取Buffer,获取Buffer会考虑Layer预期显示时间等条件,获取合适的Buffer,放弃来不及显示的Buffer。
然后判断获取的Buffer是否符合条件,不符合条件则拒绝更新。
最后将获取的Buffer信息更新到GLConsumer中,然后释放掉旧的Buffer,就的Buffer重新放回队列,等待生产者dequeue。 - 步骤5:SurfaceFlinger在图像合成的过程中,调用依次Layer的onDraw方法填充纹理,此时会调用SurfaceFlingerConsumer的方法,将上一步保存的图像信息填充到纹理中,等待合成。