- 公众号:阿豪讲Framework
- 系统教程:ahaoframework.tech/
- 进 Android Framework 技术交流群加微信 zzh0838,备注进群
1. onFrameAvailable 整体流程
前文说到 onFrameAvailable 中会先调用 acquireNextBufferLocked 函数, 其实现如下
void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr;
SurfaceComposerClient::Transaction* prevTransaction = nullptr;
{
UNIQUE_LOCK_WITH_ASSERTION(mMutex);
BBQ_TRACE();
bool waitForTransactionCallback = !mSyncedFrameNumbers.empty();
const bool syncTransactionSet = mTransactionReadyCallback != nullptr;
BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet));
if (syncTransactionSet) {
// If we are going to re-use the same mSyncTransaction, release the buffer that may
// already be set in the Transaction. This is to allow us a free slot early to continue
// processing a new buffer.
if (!mAcquireSingleBuffer) {
auto bufferData = mSyncTransaction->getAndClearBuffer(mSurfaceControl);
if (bufferData) {
BQA_LOGD("Releasing previous buffer when syncing: framenumber=%" PRIu64,
bufferData->frameNumber);
releaseBuffer(bufferData->generateReleaseCallbackId(),
bufferData->acquireFence);
}
}
if (waitForTransactionCallback) {
// We are waiting on a previous sync's transaction callback so allow another sync
// transaction to proceed.
//
// We need to first flush out the transactions that were in between the two syncs.
// We do this by merging them into mSyncTransaction so any buffer merging will get
// a release callback invoked.
while (mNumFrameAvailable > 0) {
// flush out the shadow queue
acquireAndReleaseBuffer();
}
} else {
// Make sure the frame available count is 0 before proceeding with a sync to ensure
// the correct frame is used for the sync. The only way mNumFrameAvailable would be
// greater than 0 is if we already ran out of buffers previously. This means we
// need to flush the buffers before proceeding with the sync.
while (mNumFrameAvailable > 0) {
BQA_LOGD("waiting until no queued buffers");
mCallbackCV.wait(_lock);
}
}
}
// add to shadow queue
mNumFrameAvailable++;
if (waitForTransactionCallback && mNumFrameAvailable >= 2) {
acquireAndReleaseBuffer();
}
ATRACE_INT(mQueuedBufferTrace.c_str(),
mNumFrameAvailable + mNumAcquired - mPendingRelease.size());
BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " syncTransactionSet=%s",
item.mFrameNumber, boolToString(syncTransactionSet));
if (syncTransactionSet) {
// Add to mSyncedFrameNumbers before waiting in case any buffers are released
// while waiting for a free buffer. The release and commit callback will try to
// acquire buffers if there are any available, but we don't want it to acquire
// in the case where a sync transaction wants the buffer.
mSyncedFrameNumbers.emplace(item.mFrameNumber);
// If there's no available buffer and we're in a sync transaction, we need to wait
// instead of returning since we guarantee a buffer will be acquired for the sync.
// 获取 buffer ,构建并提交事务对象
while (acquireNextBufferLocked(mSyncTransaction) == BufferQueue::NO_BUFFER_AVAILABLE) {
BQA_LOGD("waiting for available buffer");
mCallbackCV.wait(_lock);
}
// Only need a commit callback when syncing to ensure the buffer that's synced has been
// sent to SF
incStrong((void*)transactionCommittedCallbackThunk);
mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
static_cast<void*>(this));
if (mAcquireSingleBuffer) {
prevCallback = mTransactionReadyCallback;
prevTransaction = mSyncTransaction;
mTransactionReadyCallback = nullptr;
mSyncTransaction = nullptr;
}
} else if (!waitForTransactionCallback) { // 走这里
acquireNextBufferLocked(std::nullopt);
}
}
if (prevCallback) {
prevCallback(prevTransaction);
}
}
这里代码考虑了多种情况,在我们的示例代码这里会用到 acquireNextBufferLocked:
status_t BLASTBufferQueue::acquireNextBufferLocked(
const std::optional<SurfaceComposerClient::Transaction*> transaction) {
//......
// 准备事务对象 Transaction
SurfaceComposerClient::Transaction localTransaction;
bool applyTransaction = true;
SurfaceComposerClient::Transaction* t = &localTransaction;
if (transaction) {
t = *transaction;
applyTransaction = false;
}
// 调用 acquireBuffer 函数 从队列中获取到一个 BufferItem 对象
BufferItem bufferItem;
status_t status =
mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
//......
auto buffer = bufferItem.mGraphicBuffer;
mNumFrameAvailable--;
// ......
mNumAcquired++;
mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
ReleaseCallbackId releaseCallbackId(buffer->getId(), mLastAcquiredFrameNumber);
mSubmitted[releaseCallbackId] = bufferItem;
bool needsDisconnect = false;
mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
// if producer disconnected before, notify SurfaceFlinger
if (needsDisconnect) {
t->notifyProducerDisconnect(mSurfaceControl);
}
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
// Only update mSize for destination bounds if the incoming buffer matches the requested size.
// Otherwise, it could cause stretching since the destination bounds will update before the
// buffer with the new size is acquired.
if (mRequestedSize == getBufferSize(bufferItem) ||
bufferItem.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
mSize = mRequestedSize;
}
Rect crop = computeCrop(bufferItem);
mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
bufferItem.mScalingMode, crop);
// 构造一个回调对象
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
// 这里会同时拿到 bufferItem 中的 fence 对象
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
// t 是准备提交给 SurfaceFlinger 的事务对象
// 根据 bufferItem 来配置
// 注意这里传入了回调对象
t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, mProducerId,
releaseBufferCallback);
t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
if (mUpdateDestinationFrame) {
t->setDestinationFrame(mSurfaceControl, Rect(mSize));
} else {
const bool ignoreDestinationFrame =
bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE;
t->setFlags(mSurfaceControl,
ignoreDestinationFrame ? layer_state_t::eIgnoreDestinationFrame : 0,
layer_state_t::eIgnoreDestinationFrame);
}
t->setBufferCrop(mSurfaceControl, crop);
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
if (!bufferItem.mIsAutoTimestamp) {
t->setDesiredPresentTime(bufferItem.mTimestamp);
}
// Drop stale frame timeline infos
while (!mPendingFrameTimelines.empty() &&
mPendingFrameTimelines.front().first < bufferItem.mFrameNumber) {
ATRACE_FORMAT_INSTANT("dropping stale frameNumber: %" PRIu64 " vsyncId: %" PRId64,
mPendingFrameTimelines.front().first,
mPendingFrameTimelines.front().second.vsyncId);
mPendingFrameTimelines.pop();
}
if (!mPendingFrameTimelines.empty() &&
mPendingFrameTimelines.front().first == bufferItem.mFrameNumber) {
ATRACE_FORMAT_INSTANT("Transaction::setFrameTimelineInfo frameNumber: %" PRIu64
" vsyncId: %" PRId64,
bufferItem.mFrameNumber,
mPendingFrameTimelines.front().second.vsyncId);
t->setFrameTimelineInfo(mPendingFrameTimelines.front().second);
mPendingFrameTimelines.pop();
}
{
std::lock_guard _lock{mTimestampMutex};
auto dequeueTime = mDequeueTimestamps.find(buffer->getId());
if (dequeueTime != mDequeueTimestamps.end()) {
Parcel p;
p.writeInt64(dequeueTime->second);
t->setMetadata(mSurfaceControl, gui::METADATA_DEQUEUE_TIME, p);
mDequeueTimestamps.erase(dequeueTime);
}
}
mergePendingTransactions(t, bufferItem.mFrameNumber);
if (applyTransaction) { // 进入分支
// All transactions on our apply token are one-way. See comment on mAppliedLastTransaction
// 提交事务
t->setApplyToken(mApplyToken).apply(false, true);
mAppliedLastTransaction = true;
mLastAppliedFrameNumber = bufferItem.mFrameNumber;
} else {
// 设置 barrier
t->setBufferHasBarrier(mSurfaceControl, mLastAppliedFrameNumber);
mAppliedLastTransaction = false;
}
BQA_LOGV("acquireNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
" applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d"
" graphicBufferId=%" PRIu64 "%s transform=%d",
mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction),
bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "",
static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(),
bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform);
return OK;
}
acquireNextBufferLocked 函数中会调用 BufferQueueConsumer::acquireBuffer 从队列中取出 BufferItem,接着取出 BufferItem 中的 GraphicBuffer 和 Fence 对象,然后构建事务对象 SurfaceComposerClient::Transaction,构建过程中会把 GraphicBuffer 和 Fence 对象以及一个回调对象 transactionCallbackThunk 都传入事务对象中,然后执行 apply 提交给 sf。
这里的 fence 是 App 调用 queueBuffer 的时候传入的,App 渲染完成后会调用该 fence 的 signal,通知到 sf 可以渲染这个 buffer 了。
BufferQueueConsumer::acquireBuffer 过程分析
接下来我们就来看 acquireBuffer 获取 buffer 的过程。
acquireBuffer() 从 mQueue 队列中取出 1 个 BufferItem,并作为出参返回给调用者,同时修改该 BufferItem 对应的 slot 状态:QUEUED —> ACQUIRED。
动图来自 blog.csdn.net/hexiaolong2…
acquireBuffer()从mQueue队列中取出1个BufferItem,并作为出参返回给调用者,同时修改该 BufferItem 对应的 slot 状态:QUEUED —> ACQUIRED。
源码实现如下:
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.
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()) {
// 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.
//
// 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.
// 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;
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());
if (!front->mIsStale) {
// Front buffer is still in mSlots, so mark the slot as 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;
}
// Don't put the shared buffer on the free list
if (!mSlots[front->mSlot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(front->mSlot);
mCore->mFreeBuffers.push_back(front->mSlot);
}
if (mCore->mBufferReleasedCbEnabled) {
listener = mCore->mConnectedProducerListener;
}
++numDroppedBuffers;
}
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
}
// 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;
// 共享Buffer模式下处理
if (sharedBufferAvailable && mCore->mQueue.empty()) {
// make sure the buffer has finished allocating before acquiring it
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;
}
主要就是这几件事情:
- 判断BufferQueueCore中的mQueue是否为空,mQueue就是前面 BufferQueueProducer调用queueBuffer函数时,将buffer入队列的容器;
- 取出对应的BufferSlot(会有一些判断规则,舍弃一些buffer);
- 将BufferState改为acquire状态;
- 将该Buffer从mQueue中移除;
releaseBufferCallback 回调分析
消费者 acquire 拿到 buffer 后又是怎样通知 release buffer 呢?
BLASTBufferQueue::acquireNextBufferLocked 函数中获取到 buffer 后,设置事务对象时会调用一个 setBuffer 函数,这个函数的最后一个参数 releaseBufferCallback 用于回调。
t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, mProducerId,
releaseBufferCallback);
releaseBufferCallback 由 releaseBufferCallbackThunk 函数构造:
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
SF 消费完这个 buffer,就会调用到这个回调函数。
关于 sf 如何消费 buffer 以及如何调用到回调函数,还有怎么利用 fence 来等待 GPU 合成等细节我们会在后续的章节来讲解(会涉及一些 vsync 的内容,讲解了 vsync 在来分析这一块),这里我们把 sf 消费 buffer 以及调用回调函数的过程作为黑盒即可。
目前我们知道 sf 消费完 buffer 后就会去调用回调函数:
tatic void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const ReleaseCallbackId& id,
const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount) {
sp<BLASTBufferQueue> blastBufferQueue = context.promote();
if (blastBufferQueue) {
// 调用到这里
blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
} else {
ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str());
}
}
回调会调用到 BLASTBufferQueue 的 releaseBufferCallback 函数,有兴趣的可以跟下这个函数,最后会调用到 BufferQueueConsumer::releaseBuffer 函数:
BufferQueueConsumer::releaseBuffer 过程分析
- releaseBuffer()根据调用者传入的 slot 参数,将其对应的 BufferSlot 状态从 ACQUIRED 修改为 FREE,并将该 slot 从 mActiveBuffers 中迁移到 mFreeBuffers 中。注意,这里并没有对该 slot 绑定的 buffer 进行任何解绑操作。
- 调用 Producer 的 Listener 监听函数,通知 Producer 可以 dequeueBuffer 了。
源码实现如下:
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;
// fence 存到 bufferSlot 中
// 后续 App 又会取到
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;
}
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。
ProducerListener 通知 Producer
最后一个疑问?ProducerListener 如何通知到 Producer,通过回调:
listener->onBufferReleased(); //通知 producer
listener 来自 BuffeQueueCore 的 mConnectedProducerListener 成员。
listener = mCore->mConnectedProducerListener;
那么 mCore->mConnectedProducerListener 是在哪里被赋值的呢?
示例代码中有这样一句代码:
igbProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &qbOutput);
接着看 connect 函数实现:
status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp,
QueueBufferOutput* output) override {
if (!listener) {
return BufferQueueProducer::connect(listener, api, producerControlledByApp, output);
}
// listener 不为空
// 把 Listener 包装成 AsyncProducerListener
return BufferQueueProducer::connect(new AsyncProducerListener(listener), api,
producerControlledByApp, output);
}
接着调用 BufferQueueProducer::connect 函数:
status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput *output) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
BQ_LOGV("connect: api=%d producerControlledByApp=%s", api,
producerControlledByApp ? "true" : "false");
if (mCore->mIsAbandoned) {
BQ_LOGE("connect: BufferQueue has been abandoned");
return NO_INIT;
}
if (mCore->mConsumerListener == nullptr) {
BQ_LOGE("connect: BufferQueue has no consumer");
return NO_INIT;
}
if (output == nullptr) {
BQ_LOGE("connect: output was NULL");
return BAD_VALUE;
}
if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("connect: already connected (cur=%d req=%d)",
mCore->mConnectedApi, api);
return BAD_VALUE;
}
int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
mDequeueTimeout < 0 ?
mCore->mConsumerControlledByApp && producerControlledByApp : false,
mCore->mMaxBufferCount) -
mCore->getMaxBufferCountLocked();
if (!mCore->adjustAvailableSlotsLocked(delta)) {
BQ_LOGE("connect: BufferQueue failed to adjust the number of available "
"slots. Delta = %d", delta);
return BAD_VALUE;
}
int status = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
case NATIVE_WINDOW_API_CPU: // 走这个 case
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
mCore->mConnectedApi = api;
output->width = mCore->mDefaultWidth;
output->height = mCore->mDefaultHeight;
output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint;
output->numPendingBuffers =
static_cast<uint32_t>(mCore->mQueue.size());
output->nextFrameNumber = mCore->mFrameCounter + 1;
output->bufferReplaced = false;
output->maxBufferCount = mCore->mMaxBufferCount;
if (listener != nullptr) {
// Set up a death notification so that we can disconnect
// automatically if the remote producer dies
#ifndef NO_BINDER
if (IInterface::asBinder(listener)->remoteBinder() != nullptr) {
status = IInterface::asBinder(listener)->linkToDeath(
static_cast<IBinder::DeathRecipient*>(this));
if (status != NO_ERROR) {
BQ_LOGE("connect: linkToDeath failed: %s (%d)",
strerror(-status), status);
}
mCore->mLinkedToDeath = listener;
}
#endif
// 重点
mCore->mConnectedProducerListener = listener;
mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify();
}
break;
default:
BQ_LOGE("connect: unknown API %d", api);
status = BAD_VALUE;
break;
}
mCore->mConnectedPid = BufferQueueThreadState::getCallingPid();
mCore->mBufferHasBeenQueued = false;
mCore->mDequeueBufferCannotBlock = false;
mCore->mQueueBufferCanDrop = false;
mCore->mLegacyBufferDrop = true;
if (mCore->mConsumerControlledByApp && producerControlledByApp) {
mCore->mDequeueBufferCannotBlock = mDequeueTimeout < 0;
mCore->mQueueBufferCanDrop = mDequeueTimeout <= 0;
}
mCore->mAllowAllocation = true;
VALIDATE_CONSISTENCY();
return status;
}
所以回调的 Listener 就是 StubProducerListener
class StubProducerListener : public BnProducerListener {
public:
virtual ~StubProducerListener();
virtual void onBufferReleased() {}
virtual bool needsReleaseNotify() { return false; }
};
不过 onBufferReleased 中,其实什么都没做。
所以这里回调了一个寂寞。实际大多数情况下,Producer 需要主动去请求 buffer。