上一篇文章分析了生产者-消费者模型,构成此模型最重要的三个类就是生产者BufferQueueProducer,消费者BufferQueueConsumer,buffer队列BufferQueue,而buffer队列的核心就是BufferQueueCore。
本篇文章来分析一下dequeueBuffer这个函数,这个函数的作用是应用程序一端请求绘制图像时,向BufferQueue中申请一块可用的GraphicBuffer,有了这个buffer就可以绘制图像数据了。
在分析这个函数之前先来看看BufferQueueCore中维护的许多生产者-消费者模型需要用到的基本数据结构,首先来看看成员变量Fifo,如下所示:
typedef Vector<BufferItem> Fifo;
这是一个BufferItem的Vector,BufferItem是用来封装生产者生产的具体图形信息的,每次queueBuffer时都会创建一个,我们说的BufferQueue队列其实就是这个数据结构,使用如下成员变量mQueue来表示的
// mQueue is a FIFO of queued buffers used in synchronous mode.
Fifo mQueue;
再来看看成员变量mSlots:
BufferQueueDefs::SlotsType mSlots;
BufferQueueDefs::SlotsTyp定义在BufferQueueDefs.h中:
namespace BufferQueueDefs {
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
}
其实mSlots就是一个BufferSlot数组,大小为NUM_BUFFER_SLOTS等于64,BufferSlot主要是用来绑定GraphicBuffer的,一个BufferSlot绑定一个GraphicBuffer,它很重要,它里面还有一个BufferState专门用来描述当前存储的这个GraphicBuffer的状态:
BufferState()
: mDequeueCount(0),
mQueueCount(0),
mAcquireCount(0),
mShared(false) {
}
// | mShared | mDequeueCount | mQueueCount | mAcquireCount |
// --------|---------|---------------|-------------|---------------|
// FREE | false | 0 | 0 | 0 |
// DEQUEUED| false | 1 | 0 | 0 |
// QUEUED | false | 0 | 1 | 0 |
// ACQUIRED| false | 0 | 0 | 1 |
// SHARED | true | any | any | any |
//
BufferState的5种状态:FREE、 DEQUEUED、 QUEUED、 ACQUIRED、 SHARED,状态由引用计数来表示的,例如mDequeueCount为1,mShared为false,mQueueCount和mAcquireCount都为0则表示状态为DEQUEUED。
再看看成员变量mFreeSlots:
// mFreeSlots contains all of the slots which are FREE and do not currently
// have a buffer attached.
std::set<int> mFreeSlots;
mFreeSlots代表所有没有绑定GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE。
继续看成员变量mFreeBuffers:
// mFreeBuffers contains all of the slots which are FREE and currently have
// a buffer attached.
std::list<int> mFreeBuffers;
mFreeBuffers代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE。
继续看成员变量mActiveBuffers:
// mActiveBuffers contains all slots which have a non-FREE buffer attached.
std::set<int> mActiveBuffers;
mActiveBuffers代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态不为FREE,可以是另外四种状态的任意一种。
继续看成员变量mUnusedSlots:
// mUnusedSlots contains all slots that are currently unused. They should be
// free and not have a buffer attached.
std::list<int> mUnusedSlots;
mUnusedSlots代表当前没有使用的BufferSlot集合。
需要注意是以上的数据结构存储的都是BufferSlot的index
这几个数据结构都是为了给BufferSlot分类,以便获取GraphicBuffer时更加高效。
接着我们分析申请GraphicBuffer的函数dequeueBuffer,从Surface.cpp的dequeueBuffer为入口开始,这个函数比较多,分部分来看看
dequeueBuffer
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
ATRACE_CALL();
ALOGV("Surface::dequeueBuffer");
uint32_t reqWidth;
uint32_t reqHeight;
PixelFormat reqFormat;
uint64_t reqUsage;
bool enableFrameTimestamps;
{
Mutex::Autolock lock(mMutex);
if (mReportRemovedBuffers) {
mRemovedBuffers.clear();
}
reqWidth = mReqWidth ? mReqWidth : mUserWidth;
reqHeight = mReqHeight ? mReqHeight : mUserHeight;
reqFormat = mReqFormat;
reqUsage = mReqUsage;
enableFrameTimestamps = mEnableFrameTimestamps;
if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot !=
BufferItem::INVALID_BUFFER_SLOT) {
sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
if (gbuf != nullptr) {
*buffer = gbuf.get();
*fenceFd = -1;
return OK;
}
}
} // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer
......
}
第一部分主要是给一些buffer的参数设置,这些值由外部应用程序设置,如buffer宽高,格式等,接着如果满足mSharedBufferMode等一些条件则通过index为mSharedBufferSlot直接从mSlots中获取buffer,不太清楚mSharedBufferMode这是一种什么模式,默认值为false,想必是外部应用程序请求的,暂时不管了
接着看第二部分,我们重点需要分析的dequeueBuffer函数调用:
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
......
int buf = -1;
sp<Fence> fence;
nsecs_t startTime = systemTime();
FrameEventHistoryDelta frameTimestamps;
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
reqFormat, reqUsage, &mBufferAge,
enableFrameTimestamps ? &frameTimestamps
: nullptr);
......
Fence和资源同步相关,其实可以看到dequeueBuffer的很多参数都是生产者这边传递过去对buffer的一些设置,重要的是buf这个参数,它是个int类型,代表dequeueBuffer获取到的BufferSlot的下标,前面我们分析过,BufferQueueCore中有几个用来管理BufferSlot的数据结构mFreeSlots,mFreeBuffers等保存的都是下标,这里将buf传递过去,最终获取到可用BufferSlot的下标,再根据下标从mSlots中获取BufferSlot,这点等下再说,先看看dequeueBuffer获取BufferSlot的具体规则是什么?
调用的是生产者BufferQueueProducer的dequeueBuffer函数:
BufferQueueProducer::dequeueBuffer
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
ATRACE_CALL();
{ // Autolock scope
std::lock_guard<std::mutex> lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("dequeueBuffer: BufferQueue has no connected producer");
return NO_INIT;
}
} // Autolock scope
BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#" PRIx64, width, height, format, usage);
if ((width && !height) || (!width && height)) {
BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
return BAD_VALUE;
}
status_t returnFlags = NO_ERROR;
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
bool attachedByConsumer = false;
{ // Autolock scope
std::unique_lock<std::mutex> lock(mCore->mMutex);
// If we don't have a free buffer, but we are currently allocating, we wait until allocation
// is finished such that we don't allocate in parallel.
if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
mDequeueWaitingForAllocation = true;
mCore->waitWhileAllocatingLocked(lock);
mDequeueWaitingForAllocation = false;
mDequeueWaitingForAllocationCondition.notify_all();
}
if (format == 0) {
format = mCore->mDefaultBufferFormat;
}
// Enable the usage bits the consumer requested
usage |= mCore->mConsumerUsageBits;
const bool useDefaultSize = !width && !height;
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
}
......
这个函数代码也非常多,我们分部分来看,mCore->mIsAbandoned代表当前BufferQueue的状态,如果不可用直接return,mCore->mConnectedApi这个是从Surface那边传递获取的,是否与BufferQueue建立连接,通常是调用native_window_api_connect这个API实现的,如果没有建立连接也直接return,接着就是检查宽高的合法性,定义好最终的返回值returnFlags,EGLDisplay,EGLSyncKHR暂时不清楚用来干嘛的,接着来到如下段代码:
if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
mDequeueWaitingForAllocation = true;
mCore->waitWhileAllocatingLocked(lock);
mDequeueWaitingForAllocation = false;
mDequeueWaitingForAllocationCondition.notify_all();
}
mFreeBuffers前面已经分析过,代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE,如果mFreeBuffers为空(代表当前没有绑定了GraphicBuffer的BufferSlot)并且当前正在为GraphicBuffer分配内存空间,则调用waitWhileAllocatingLocked等待空间分配,等待\唤醒机制利用的是C++的条件变量,接着如果format == 0则使用mDefaultBufferFormat,接着如果宽高为0则使用BufferQueueCore的默认宽高。
第一部分已经分析完了,接着看第二部分:
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
......
int found = BufferItem::INVALID_BUFFER_SLOT;
while (found == BufferItem::INVALID_BUFFER_SLOT) {
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
if (status != NO_ERROR) {
return status;
}
// This should not happen
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
BQ_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY;
}
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
// If we are not allowed to allocate new buffers,
// waitForFreeSlotThenRelock must have returned a slot containing a
// buffer. If this buffer would require reallocation to meet the
// requested attributes, we free it and attempt to get another one.
if (!mCore->mAllowAllocation) {
if (buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
if (mCore->mSharedBufferSlot == found) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a sharedbuffer");
return BAD_VALUE;
}
mCore->mFreeSlots.insert(found);
mCore->clearBufferSlotLocked(found);
found = BufferItem::INVALID_BUFFER_SLOT;
continue;
}
}
}
......
}
这第二部分就是寻找可用BufferSlot的核心代码了,通过一个while循环不断的查找,直到found != BufferItem::INVALID_BUFFER_SLOT,首先found初始化状态为BufferItem::INVALID_BUFFER_SLOT,进入While循环,调用核心函数waitForFreeSlotThenRelock,这个函数代码也挺多的,把这个函数分三部分来分析,首先看第一部分。
waitForFreeSlotThenRelock
status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
std::unique_lock<std::mutex>& lock, int* found) const {
auto callerString = (caller == FreeSlotCaller::Dequeue) ?
"dequeueBuffer" : "attachBuffer";
bool tryAgain = true;
while (tryAgain) {
if (mCore->mIsAbandoned) {
BQ_LOGE("%s: BufferQueue has been abandoned", callerString);
return NO_INIT;
}
int dequeuedCount = 0;
int acquiredCount = 0;
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isDequeued()) {
++dequeuedCount;
}
if (mSlots[s].mBufferState.isAcquired()) {
++acquiredCount;
}
}
// Producers are not allowed to dequeue more than
// mMaxDequeuedBufferCount buffers.
// This check is only done if a buffer has already been queued
if (mCore->mBufferHasBeenQueued &&
dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
// Supress error logs when timeout is non-negative.
if (mDequeueTimeout < 0) {
BQ_LOGE("%s: attempting to exceed the max dequeued buffer "
"count (%d)", callerString,
mCore->mMaxDequeuedBufferCount);
}
return INVALID_OPERATION;
}
*found = BufferQueueCore::INVALID_BUFFER_SLOT;
......
}
return NO_ERROR;
这整个函数就是一个while循环,直到找到可用BufferSlot或者发生错误,首先获取当前调用此函数的是dequeueBuffer还是attachBuffer,定义while的开关tryAgain默认为true,会一直尝试获取,进入while循环,如果当前BufferQueue已经被弃用则直接return,
接着看看如下小段代码:
int dequeuedCount = 0;
int acquiredCount = 0;
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isDequeued()) {
++dequeuedCount;
}
if (mSlots[s].mBufferState.isAcquired()) {
++acquiredCount;
}
}
定义了两个值dequeuedCount和acquiredCount分别用来统计mActiveBuffers(所有绑定了GraphicBuffer的BufferSlot集合,并且状态不为FREE的BufferSlot)中,状态为DEQUEUED和状态为ACQUIRED的BufferSlot的数量。
接着继续看一小段代码:
if (mCore->mBufferHasBeenQueued &&
dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
// Supress error logs when timeout is non-negative.
if (mDequeueTimeout < 0) {
BQ_LOGE("%s: attempting to exceed the max dequeued buffer "
"count (%d)", callerString,
mCore->mMaxDequeuedBufferCount);
}
return INVALID_OPERATION;
}
这段代码主要是检查生产者不允许申请超过mMaxDequeuedBufferCount数量的BufferSlot
接着看第二部分代码:
status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
std::unique_lock<std::mutex>& lock, int* found) const {
......
const int maxBufferCount = mCore->getMaxBufferCountLocked();
bool tooManyBuffers = mCore->mQueue.size()
> static_cast<size_t>(maxBufferCount);
if (tooManyBuffers) {
BQ_LOGV("%s: queue size is %zu, waiting", callerString,
mCore->mQueue.size());
} else {
// If in shared buffer mode and a shared buffer exists, always
// return it.
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = mCore->mSharedBufferSlot;
} else {
if (caller == FreeSlotCaller::Dequeue) {
// If we're calling this from dequeue, prefer free buffers
int slot = getFreeBufferLocked();
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else if (mCore->mAllowAllocation) {
*found = getFreeSlotLocked();
}
} else {
// If we're calling this from attach, prefer free slots
int slot = getFreeSlotLocked();
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else {
*found = getFreeBufferLocked();
}
}
}
}
......
return NO_ERROR;
}
首先获取BufferQueue最大buffer数量,一般为2或者3,如果当前mQueue的大小已经大于最大buffer数量则应该等待buffer的消费,mQueue的大小会在queueBuffer时增加,queueBuffer这个函数在下一篇文章分析,接着看else分支:
首先如果当前使用的是共享buffer模式,并且mSharedBufferSlot是有效的,则直接返回mCore->mSharedBufferSlot,关于共享buffer模式不太了解,接着如果不是共享buffer模式:调用者是dequeueBuffer函数则首先调用getFreeBufferLocked从mFreeBuffers头部获取BufferSlot,这段代码也比较简单:
int BufferQueueProducer::getFreeBufferLocked() const {
if (mCore->mFreeBuffers.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
int slot = mCore->mFreeBuffers.front();
mCore->mFreeBuffers.pop_front();
return slot;
}
mFreeBuffers代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE。如果从mFreeBuffers能找到可用BufferSlot并且是有效的则说明已经找到了,就给found赋值,接着如果没有找到则进入else if分支,代表当前没有绑定了GraphicBuffer的BufferSlot,需要重新给GraphicBuffer分配内存空间,所以else if的条件是当前是否允许分配空间,接着看getFreeSlotLocked函数:
int BufferQueueProducer::getFreeSlotLocked() const {
if (mCore->mFreeSlots.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
int slot = *(mCore->mFreeSlots.begin());
mCore->mFreeSlots.erase(slot);
return slot;
}
这个函数也比较简单,如果mFreeSlots不为空就获取mFreeSlots第一个元素,获取之后从mFreeSlots删除,mFreeSlots代表所有没有绑定GraphicBuffer的BufferSlot集合,并且BufferSlot状态为FREE。
好了else分支分析完了,我们可以知道获取BufferSlot的规律了,会优先从mFreeBuffers中寻找,找不到再从mFreeSlots寻找。
接着来看waitForFreeSlotThenRelock最后一部分代码:
status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
std::unique_lock<std::mutex>& lock, int* found) const {
......
// If no buffer is found, or if the queue has too many buffers
// outstanding, wait for a buffer to be acquired or released, or for the
// max buffer count to change.
tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) ||
tooManyBuffers;
if (tryAgain) {
// Return an error if we're in non-blocking mode (producer and
// consumer are controlled by the application).
// However, the consumer is allowed to briefly acquire an extra
// buffer (which could cause us to have to wait here), which is
// okay, since it is only used to implement an atomic acquire +
// release (e.g., in GLConsumer::updateTexImage())
if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) &&
(acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
return WOULD_BLOCK;
}
if (mDequeueTimeout >= 0) {
std::cv_status result = mCore->mDequeueCondition.wait_for(lock,
std::chrono::nanoseconds(mDequeueTimeout));
if (result == std::cv_status::timeout) {
return TIMED_OUT;
}
} else {
mCore->mDequeueCondition.wait(lock);
}
}
} // while (tryAgain)
......
}
注意这三部分都是在while循环中进行的,第二部分我们已经找到了BufferSlot,此时的BufferSlot有两种情况(不考虑共享buffer模式),一种是从mFreeBuffers中获取的已经绑定了GraphicBuffer,另一种是从mFreeSlots中获取的还没有绑定GraphicBuffer,首先来看tryAgain的赋值,如果前面没有获取到有效BufferSlot或者tooManyBuffers为true则需要tryAgain继续尝试获取,其实最后如果真的需要tryAgain更多是当前queue的buffer已经太多了,需要等待消费者acquire(非同步模式的情况,即mAsyncMode为false),到这里waitForFreeSlotThenRelock函数已经分析完了,这个函数代码多其实逻辑很简单,就是一个获取BufferSlot的规则,先从mFreeBuffers中获取,再从mFreeSlots中获取。
接着我们再回到dequeueBuffer函数的第二部分:
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
......
int found = BufferItem::INVALID_BUFFER_SLOT;
while (found == BufferItem::INVALID_BUFFER_SLOT) {
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
if (status != NO_ERROR) {
return status;
}
// This should not happen
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
BQ_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY;
}
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
// If we are not allowed to allocate new buffers,
// waitForFreeSlotThenRelock must have returned a slot containing a
// buffer. If this buffer would require reallocation to meet the
// requested attributes, we free it and attempt to get another one.
if (!mCore->mAllowAllocation) {
if (buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
if (mCore->mSharedBufferSlot == found) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a sharedbuffer");
return BAD_VALUE;
}
mCore->mFreeSlots.insert(found);
mCore->clearBufferSlotLocked(found);
found = BufferItem::INVALID_BUFFER_SLOT;
continue;
}
}
}
......
}
waitForFreeSlotThenRelock函数之后已经获取到了可用的BufferSlot(再强调一遍,获取的BufferSlot都是下标index),接着根据获取到的BufferSlot下标从mSlots中拿到BufferSlot,并通过BufferSlot绑定的GraphicBuffer创建一个
GraphicBuffer,注意此时BufferSlot绑定的GraphicBuffer有可能为空的,接着判断当前BufferQueue是否允许分配空间,如果不允许,并且当前GraphicBuffer需要分配空间(即waitForFreeSlotThenRelock函数是从mFreeSlots中获取到的BufferSlot),共享buffer模式不管,那么就重新将当前这个BufferSlot再插入mFreeSlots中,并且清空当前这个BufferSlot的各种状态,然后将found再置为BufferItem::INVALID_BUFFER_SLOT,并再进入下次循环,好了dequeueBuffer第二部分已经分析完了,总结:这部分其实就是在while循环中不断的获取BufferSlot,直到
found != BufferItem::INVALID_BUFFER_SLOT为止,
接着看dequeueBuffer函数的第三部分:
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
......
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if (mCore->mSharedBufferSlot == found &&
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
"buffer");
return BAD_VALUE;
}
if (mCore->mSharedBufferSlot != found) {
mCore->mActiveBuffers.insert(found);
}
*outSlot = found;
ATRACE_BUFFER_INDEX(found);
attachedByConsumer = mSlots[found].mNeedsReallocation;
mSlots[found].mNeedsReallocation = false;
mSlots[found].mBufferState.dequeue();
if ((buffer == nullptr) ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = nullptr;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->mBufferAge = 0;
mCore->mIsAllocating = true;
returnFlags |= BUFFER_NEEDS_REALLOCATION;
} else {
// We add 1 because that will be the frame number when this buffer
// is queued
mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
mCore->mBufferAge);
if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) {
BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
"slot=%d w=%d h=%d format=%u",
found, buffer->width, buffer->height, buffer->format);
}
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
// Don't return a fence in shared buffer mode, except for the first
// frame.
*outFence = (mCore->mSharedBufferMode &&
mCore->mSharedBufferSlot == found) ?
Fence::NO_FENCE : mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
// If shared buffer mode has just been enabled, cache the slot of the
// first buffer that is dequeued and mark it as the shared buffer.
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
BufferQueueCore::INVALID_BUFFER_SLOT) {
mCore->mSharedBufferSlot = found;
mSlots[found].mBufferState.mShared = true;
}
} // Autolock scope
......
}
首先根据found获取到BufferSlot,根据BufferSlot的GraphicBuffer创建GraphicBuffer,BufferSlot的GraphicBuffer有可能为空,共享buffer模式跳过,如果found不是mSharedBufferSlot,则将found插入mActiveBuffers,mActiveBuffers代表所有绑定了GraphicBuffer的BufferSlot集合,并且BufferSlot状态不为FREE,可以是另外四种状态的任意一种。虽说mActiveBuffers中的BufferSlot一定绑定了GraphicBuffer,但此时此刻,BufferSlot的GraphicBuffer任然可能是空的,继续看代码,这个outSlot是最终返回给Surface那一端的,接着获取当前found的BufferSlot的mNeedsReallocation,是否需要重新分配空间,然后再修改为false,接着修改当前found的BufferSlot的状态为DEQUEUED,然后我们再看接下来一小段代码:
if ((buffer == nullptr) ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = nullptr;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->mBufferAge = 0;
mCore->mIsAllocating = true;
returnFlags |= BUFFER_NEEDS_REALLOCATION;
} else {
// We add 1 because that will be the frame number when this buffer
// is queued
mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
如果found的BufferSlot并没有绑定GraphicBuffer或者GraphicBuffer需要分配空间则将found的BufferSlot的状态全部clear,置为初始状态值,否则将BufferQueueCore的mBufferAge +1,mFrameCounter和mFrameNumber一般是相等的,代表当前queue的buffer数量,eglDisplay,eglFence不太清楚具体用处,暂时跳过,这部分最后也是和共享buffer模式有关,跳过。
接着我们来看dequeue最后一部分代码:
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
......
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
width, height, format, BQ_LAYER_COUNT, usage,
{mConsumerName.string(), mConsumerName.size()});
status_t error = graphicBuffer->initCheck();
{ // Autolock scope
std::lock_guard<std::mutex> lock(mCore->mMutex);
if (error == NO_ERROR && !mCore->mIsAbandoned) {
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
}
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.notify_all();
if (error != NO_ERROR) {
mCore->mFreeSlots.insert(*outSlot);
mCore->clearBufferSlotLocked(*outSlot);
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
return error;
}
if (mCore->mIsAbandoned) {
mCore->mFreeSlots.insert(*outSlot);
mCore->clearBufferSlotLocked(*outSlot);
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
VALIDATE_CONSISTENCY();
} // Autolock scope
}
if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
if (eglFence != EGL_NO_SYNC_KHR) {
EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
1000000000);
// If something goes wrong, log the error, but return the buffer without
// synchronizing access to it. It's too late at this point to abort the
// dequeue operation.
if (result == EGL_FALSE) {
BQ_LOGE("dequeueBuffer: error %#x waiting for fence",
eglGetError());
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
BQ_LOGE("dequeueBuffer: timeout waiting for fence");
}
eglDestroySyncKHR(eglDisplay, eglFence);
}
BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",
*outSlot,
mSlots[*outSlot].mFrameNumber,
mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
if (outBufferAge) {
*outBufferAge = mCore->mBufferAge;
}
addAndGetFrameTimestamps(nullptr, outTimestamps);
return returnFlags;
}
首先判断如果GraphicBuffer需要分配空间,则new一个GraphicBuffer,关于GraphicBuffer分配空间的内容比较复杂(需要使用Gralloc HAL进行内存分配),本篇文章就不看了,new了之后会通过mIsAllocatingCondition.notify_all唤醒如果有因为mIsAllocating陷入等待的线程,还会将分配好的graphicBuffer和BufferSlot进行绑定,如果分配空间失败便会将BufferSlot插入mFreeSlots中,并通过clearBufferSlotLocked函数情况BufferSlot状态,如果BufferQueue当前已经被弃用则同样将BufferSlot插入mFreeSlots中并清空状态,接着如果attachedByConsumer为true,则添加上BUFFER_NEEDS_REALLOCATION的flag,eglDisplay, eglFence不清楚,暂时跳过,剩下的代码就不看了。
到此dequeueBuffer函数已经分析完毕,虽然代码很多,也分析了很多,但这个函数的核心就是申请BufferSlot,先从mFreeBuffers取,没取到再从mFreeSlots取,然后再看取到的BufferSlot是否绑定了GraphicBuffer,如果没有则还需要为GraphicBuffer分配内存空间,其实有很多的代码都是对异常情况的处理。
dequeueBuffer函数执行完毕之后,Surface一端就拿到了可用的BufferSlot的下标。
我们再接着看Surface的dequeueBuffer函数的剩下部分:
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
......
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
...
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
if (mReportRemovedBuffers && (gbuf != nullptr)) {
mRemovedBuffers.push_back(gbuf);
}
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
if (result != NO_ERROR) {
ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
mGraphicBufferProducer->cancelBuffer(buf, fence);
return result;
}
}
*buffer = gbuf.get();
return OK;
}
最后部分就选了上面的代码来看,首先Surface这一端创建GraphicBuffer指向BufferQueueProducer获取到的BufferSlot绑定的GraphicBuffer,接着如果刚刚dequeueBuffer函数返回的result为BUFFER_NEEDS_REALLOCATION,或者gbuf为空,则调用requestBuffer函数到BufferQueueProducer一端重新给BufferSlot绑定GraphicBuffer,代码就不看了,很简单,最后将gbuf给到*buffer返回给最终的应用层,拿到GraphicBuffer之后就可以进行各种绘制操作了。