上一篇文章分析了生產者-消費者模型,構成此模型最重要的三個類就是生產者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
之後就可以進行各種繪製操作了。