上一篇文章分析了生产者-消费者模型,构成此模型最重要的三个类就是生产者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
为入口开始,这个函数比较多,分部分来看看
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
函数:
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
,这个函数代码也挺多的,把这个函数分三部分来分析,首先看第一部分。
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
之后就可以进行各种绘制操作了。