題外話
我竟然已經寫了這個系列的十一篇文章了,雖然內容很淺顯,雖然內容很枯燥,雖然內容也許沒營養,但我為自己的堅持點贊!
一、前言
前面的兩篇文章,分別講解了Producer的處理邏輯和queue buffer後通過FrameAvailableListener通知到Consumer的基本過程。
流程已經走到了BufferQueueConsumer::acquireBuffer中,所以這篇文章聚焦Consumer的一些處理邏輯。
還是把流程圖貼上來
從流程圖中看,這篇文章就是講解右半部分的內容。
二、消費者-Consumer的相關邏輯
瞭解了 BufferQueueCore 和 BufferQueueProducer,接著看 BufferQueue 的最後一個元素:BufferQueueConsumer。
BufferQueueConsumer作為消費者的一個代表元素通過 acquireBuffer 來獲取影像緩衝區,通過 releaseBuffer 來釋放該緩衝區。
下面就分別看看 BufferQueueConsumer 中 acquireBuffer 和 releaseBuffer 兩個操作的具體流程。
2.1 程式碼位置
/frameworks/native/libs/gui/BufferQueueConsumer.cpp
2.2 acquireBuffer的邏輯
先看 acquireBuffer 的過程,上原始碼
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
ATRACE_CALL();
int numDroppedBuffers = 0;
sp<IProducerListener> listener;
{
std::unique_lock<std::mutex> 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.
// 檢查acquire的buffer的數量是否超出了限制
int numAcquiredBuffers = 0;
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isAcquired()) {
++numAcquiredBuffers;
}
}
const bool acquireNonDroppableBuffer = mCore->mAllowExtraAcquire &&
numAcquiredBuffers == mCore->mMaxAcquiredBufferCount + 1;
if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1 &&
!acquireNonDroppableBuffer) {
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.
// 檢查BufferQueueCore中的mQueue佇列是否為空
if (mCore->mQueue.empty() && !sharedBufferAvailable) {
return NO_BUFFER_AVAILABLE;
}
// 獲取BufferQueueCore中的mQueue佇列的迭代器
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()) {
// expectedPresent表示期望這個buffer什麼時候顯示到螢幕上。
// 如果buffer的期望顯示時間小於expectedPresent,我們會acquire and return這個buffer
// 如果我們不想顯示它直到expectedPresent之後,可以返回PRESENT_LATER
// 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.
//
// 安全起見,如果expectedPresent超過了buffer的期望顯示時間1秒,我們會推遲acquire
// 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.
// 檢查是否需要丟棄一些幀,主要是判斷timestamps & expectedPresent
// 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;
// desiredPresent比expectedPresent小了1 second多,或desiredPresent大於expectedPresent
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());
// 處理要drop的buffer
if (!front->mIsStale) {
// Front buffer is still in mSlots, so mark the slot as free
// 對應的BufferSlot設定為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;
}
// mActiveBuffers :繫結了GraphicBuffer且狀態為非FREE的BufferSlot集合;
// mFreeBuffers :繫結了GraphicBuffer且狀態為FREE的BufferSlot集合;
// Don't put the shared buffer on the free list
if (!mSlots[front->mSlot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(front->mSlot); // 從mActiveBuffers刪除
mCore->mFreeBuffers.push_back(front->mSlot);// 新增進mFreeBuffers
}
if (mCore->mBufferReleasedCbEnabled) {
listener = mCore->mConnectedProducerListener; // 設定生產者的監聽器
}
++numDroppedBuffers; // 計數加1,記錄drop了幾個buffer
}
mCore->mQueue.erase(front);// 從mQueue中刪除
front = mCore->mQueue.begin();// 重置front,進入下一次while迴圈
}
// 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);
ATRACE_NAME("PRESENT_LATER");
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
// 共享Buffer模式下處理
mCore->waitWhileAllocatingLocked(lock);
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->mFenceTime = FenceTime::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 if (acquireNonDroppableBuffer && front->mIsDroppable) {
BQ_LOGV("acquireBuffer: front buffer is not droppable");
return NO_BUFFER_AVAILABLE;
} else {
// 從front獲取對應的slot index
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 {
// 將BufferState狀態改為acquire
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 = nullptr;
}
//將該Buffer從mQueue中移除
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.notify_all();
ATRACE_INT(mCore->mConsumerName.string(),
static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
#endif
VALIDATE_CONSISTENCY();
}
// 回撥,通知生產者
if (listener != nullptr) {
for (int i = 0; i < numDroppedBuffers; ++i) {
listener->onBufferReleased();
}
}
return NO_ERROR;
}
acquireBuffer 函式中的邏輯也非常的清晰,原始碼中也做了詳細註釋。
主要就是這幾件事情:
- 判斷 BufferQueueCore 中的 mQueue 是否為空,mQueue 就是前面 BufferQueueProducer 呼叫 queueBuffer 函式時,將緩衝區入隊的容器;
- 取出對應的 BufferSlot(會有一些判斷規則,捨棄一些buffer);
- 將 BufferState 改為 acquire 狀態;
- 將該 Buffer 從 mQueue 中移除;
2.3 消費者acquire拿到buffer後又是怎樣通知release buffer呢?
要回答這個問題,我們需要在回到呼叫acquireBuffer的地方,即 BLASTBufferQueue::processNextBufferLocked 函式中,先看其程式碼:
void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
......
SurfaceComposerClient::Transaction localTransaction;
bool applyTransaction = true;
SurfaceComposerClient::Transaction* t = &localTransaction;
// acquireBuffer獲取要處理的buffer
BufferItem bufferItem;
status_t status =
mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
......
// 拿到了實際的GraphicBuffer了
auto buffer = bufferItem.mGraphicBuffer;
mNumFrameAvailable--;
// 某些情況下,直接releaseBuffer而無需送SurfaceFlinger合成顯示
mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
ReleaseCallbackId releaseCallbackId(buffer->getId(), mLastAcquiredFrameNumber);
mSubmitted[releaseCallbackId] = bufferItem;
....
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
// release buffer的回到函式
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
std::placeholders::_4);
t->setBuffer(mSurfaceControl, buffer, releaseCallbackId, releaseBufferCallback);
......
if (applyTransaction) {
t->setApplyToken(mApplyToken).apply();
}
}
上述程式碼,做了比較多的簡化,只保留我認為比較重要的部分。
- 呼叫acquireBuffer獲取一個BufferItem;
- 取出GraphicBuffer -- auto buffer = bufferItem.mGraphicBuffer;
- 通過事務Transaction來向SurfaceFlinger提交Buffer與圖層的屬性;
t->setBuffer(mSurfaceControl, buffer, releaseCallbackId, releaseBufferCallback);
對於setBuffer,就是設定傳遞給SF的buffer,並指定了一個releaseBufferCallback,暫時可以理解為SF消費完這個buffer,就會通過這個callback通知來釋放這個buffer。
本文作者@二的次方 2022-03-23 釋出於部落格園
在acquireBuffer中加入log,列印呼叫堆疊資訊,如下:
11-13 01:23:59.275 3016 3030 E BufferQueueConsumer: stackdump:#00 pc 000580ff /system/lib/libgui.so (android::BufferQueueConsumer::releaseBuffer(int, unsigned long long, android::sp<android::Fence> const&, void*, void*)+130)
11-13 01:23:59.275 3016 3030 E BufferQueueConsumer: stackdump:#01 pc 00059117 /system/lib/libgui.so (android::BufferQueueConsumer::releaseBuffer(int, unsigned long long, void*, void*, android::sp<android::Fence> const&)+30)
11-13 01:23:59.275 3016 3030 E BufferQueueConsumer: stackdump:#02 pc 00076d27 /system/lib/libgui.so (android::ConsumerBase::releaseBufferLocked(int, android::sp<android::GraphicBuffer>, void*, void*)+134)
11-13 01:23:59.275 3016 3030 E BufferQueueConsumer: stackdump:#03 pc 0007580d /system/lib/libgui.so (android::BufferItemConsumer::releaseBuffer(android::BufferItem const&, android::sp<android::Fence> const&)+140)
11-13 01:23:59.275 3016 3030 E BufferQueueConsumer: stackdump:#04 pc 0006c467 /system/lib/libgui.so (android::BLASTBufferQueue::releaseBufferCallback(android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int)+1362)
11-13 01:23:59.275 3016 3030 E BufferQueueConsumer: stackdump:#05 pc 0006d827 /system/lib/libgui.so (android::releaseBufferCallbackThunk(android::wp<android::BLASTBufferQueue>, android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int)+62)
11-13 01:23:59.276 3016 3030 E BufferQueueConsumer: stackdump:#06 pc 0007039b /system/lib/libgui.so (std::__1::__function::__func<std::__1::__bind<void (&)(android::wp<android::BLASTBufferQueue>, android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int), android::wp<android::BLASTBufferQueue>, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&, std::__1::placeholders::__ph<4> const&>, std::__1::allocator<std::__1::__bind<void (&)(android::wp<android::BLASTBufferQueue>, android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int), android::wp<android::BLASTBufferQueue>, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&, std::__1::placeholders::__ph<4> const&> >, void (android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int)>::operator()(android::ReleaseCallbackId const&, android::sp<android::Fence> const&,
11-13 01:23:59.276 3016 3030 E BufferQueueConsumer: stackdump:#07 pc 000a7d47 /system/lib/libgui.so (android::TransactionCompletedListener::onTransactionCompleted(android::ListenerStats)+3382)
11-13 01:23:59.276 3016 3030 E BufferQueueConsumer: stackdump:#08 pc 000925a5 /system/lib/libgui.so (int android::SafeBnInterface<android::ITransactionCompletedListener>::callLocalAsync<void (android::ITransactionCompletedListener::*)(android::ListenerStats)>(android::Parcel const&, android::Parcel*, void (android::ITransactionCompletedListener::*)(android::ListenerStats))+204)
11-13 01:23:59.276 3016 3030 E BufferQueueConsumer: stackdump:#09 pc 00028ddb /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+162)
看上面的呼叫棧,是不是一目瞭然,從遙遠的Binder來的神祕資訊觸發了這一些列的事件:
>>> releaseBufferCallbackThunk
>>> BLASTBufferQueue::releaseBufferCallback
>>> BufferItemConsumer::releaseBuffer
>>> ConsumerBase::releaseBufferLocked
>>> BufferQueueConsumer::releaseBuffer
2.4 releaseBuffer的邏輯
老規矩,直接看程式碼,是不是很簡單啊!
status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
EGLSyncKHR eglFence) {
ATRACE_CALL();
ATRACE_BUFFER_INDEX(slot);
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
releaseFence == nullptr) {
BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
releaseFence.get());
return BAD_VALUE;
}
sp<IProducerListener> listener;
{ // Autolock scope
std::lock_guard<std::mutex> lock(mCore->mMutex);
// If the frame number has changed because the buffer has been reallocated,
// we can ignore this releaseBuffer for the old buffer.
// Ignore this for the shared buffer where the frame number can easily
// get out of sync due to the buffer being queued and acquired at the
// same time.
if (frameNumber != mSlots[slot].mFrameNumber &&
!mSlots[slot].mBufferState.isShared()) {
return STALE_BUFFER_SLOT;
}
if (!mSlots[slot].mBufferState.isAcquired()) {
BQ_LOGE("releaseBuffer: attempted to release buffer slot %d "
"but its state was %s", slot,
mSlots[slot].mBufferState.string());
return BAD_VALUE;
}
mSlots[slot].mEglDisplay = eglDisplay;
mSlots[slot].mEglFence = eglFence;
mSlots[slot].mFence = releaseFence;
mSlots[slot].mBufferState.release();//置為FREE狀態
// 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[slot].mBufferState.isFree()) {
mSlots[slot].mBufferState.mShared = false;
}
// Don't put the shared buffer on the free list.
if (!mSlots[slot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(slot);// 從mActiveBuffers中刪除
mCore->mFreeBuffers.push_back(slot);//加入到mFreeBuffers中
}
if (mCore->mBufferReleasedCbEnabled) {
listener = mCore->mConnectedProducerListener; / 設定listener
}
BQ_LOGV("releaseBuffer: releasing slot %d", slot);
// 喚醒等待的執行緒
mCore->mDequeueCondition.notify_all();
VALIDATE_CONSISTENCY();
} // Autolock scope
// Call back without lock held
if (listener != nullptr) {
listener->onBufferReleased(); //通知producer
}
return NO_ERROR;
}
releaseBuffer方法的流程相對簡單:
-
slot就是需要釋放的BufferSlot的序號;
-
Buffer的FrameNumber變了,可能Buffer已經重新分配,這個是不用管;
-
只能釋放acquire狀態的buffer序號,釋放後是Buffer放會mFreeBuffers中;
-
releaseFence,從consumer那邊傳過來,producer可以dequeue mFreeBuffers中的buffer,但是隻有releaseFence發訊號出來後,consumer才真正用完,producer才可以寫;
-
最後通過listener通知producer。
2.5 ProducerListener是怎樣工作的?
在前面的講解中,有幾處都有出現 listener->onBufferReleased() ,意思是通知producer有buffer釋放了。這個listener是在哪裡設定的?onBufferReleased又做了哪些工作呢?接下來分析
定義:/frameworks/native/libs/gui/include/gui/IProducerListener.h
首先我們看到這張類圖:
1. 在BufferQueueCore中有成員 sp<IProducerListener> mConnectedProducerListener,它就是用來處理onBufferReleased事件的;
2. mConnectedProducerListener是在哪裡被設定的呢?答案是 BufferQueueProducer::connect;
3. 根據呼叫棧來追蹤:
11-13 01:20:19.388 2955 3013 E BufferQueueProducer: stackdump:#00 pc 0005e667 /system/lib/libgui.so (android::BufferQueueProducer::connect(android::sp<android::IProducerListener> const&, int, bool, android::IGraphicBufferProducer::QueueBufferOutput*)+1018)
11-13 01:20:19.388 2955 3013 E BufferQueueProducer: stackdump:#01 pc 0006ee41 /system/lib/libgui.so (android::BBQBufferQueueProducer::connect(android::sp<android::IProducerListener> const&, int, bool, android::IGraphicBufferProducer::QueueBufferOutput*)+176)
11-13 01:20:19.388 2955 3013 E BufferQueueProducer: stackdump:#02 pc 000a268b /system/lib/libgui.so (android::Surface::connect(int, android::sp<android::IProducerListener> const&, bool)+138)
11-13 01:20:19.388 2955 3013 E BufferQueueProducer: stackdump:#03 pc 0009dd61 /system/lib/libgui.so (android::Surface::hook_perform(ANativeWindow*, int, ...)+128)
4. 可以肯定,是執行 native_window_api_connect() 一路走下來的。沿著這條路,看看listener是哪裡產生的呢?
看起來是這個位置:
int Surface::connect(int api) {
static sp<IProducerListener> listener = new StubProducerListener();
return connect(api, listener);
}
5. 不過,奇怪的事情發生了,StubProducerListener看起來沒有任何操作,乖乖(這一點還是很奇怪的)
6. BLASTBufferQueue中還有使用AsyncProducerListener做一層封裝,實現非同步處理;
class StubProducerListener : public BnProducerListener {
public:
virtual ~StubProducerListener();
virtual void onBufferReleased() {}
virtual bool needsReleaseNotify() { return false; }
};
三、小結
BufferQueue的運作流程到這裡就算講完了。生產者做了什麼事情?消費者做了什麼事情?圖形快取是怎樣流轉的?狀態是怎樣變化的?在幾篇文章中基本上都有做了或簡單或詳細的介紹。通過BufferQueue的幾篇文章,幫助自己建立起基本的邏輯框架,為我們後續研究和分析問題奠定基礎。