前言
BufferQueueConsumer类实现了IGraphicBufferConsumer接口,是跟BBQ连接的图形内容消费者对象。
在BBQ的实现架构中,BLASTBufferQueue对象中通过BufferQueueConsumer对象获取到GraphicBuffer,然后通过Transaction::setBuffer()
传递给surfaceflinger进程,进行合成与显示。
但BLASTBufferQueue
并没有直接和BufferQueueConsumer
进行交互,而是通过BufferItemConsumer
对象通知BufferQueueConsumer
从BBQ队列中获取可用GraphicBuffer并返回。BLASTBufferQueue
作为BBQ的抽象实现类,会根据客户端需要进行特殊的场景控制、GraphicBuffer调控等操作。BufferQueueConsumer
只负责执行通用操作,利用"分层"思想,通过BufferItemConsumer
这个中间件,来简化和内聚两者的主要职责。
BufferQueueConsumer
主要负责以下几个操作:
- acquireBuffer:从BBQ队列中获取已经由图形内容生产方填充的Buffer,并获得其所有权;
- releaseBuffer:将Buffer从Consumer中释放回BBQ队列,并将其所有权交还给BBQ队列。
一、acquireBuffer操作
acquireBuffer
试图从mCore->mQueue
中获取下一个待消费的BufferItem所有权,如果获取成功,会将mCore->mSlots
中的BufferSlot状态设置为ACQUIRED
状态。同时在BBQ中会将其携带的GraphicBuffer通过Transaction传递给surfaceflinger进行合成显示。
cpp
// frameworks/native/include/gui/IGraphicBufferConsumer.h
virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
uint64_t maxFrameNumber = 0) = 0;
参数
-
presentWhen:表示该Buffer期望何时显示在屏幕上的时间戳(纳秒)。
- 默认presentWhen为0;
- 如果presentWhenBuffer的时间戳距离
BufferItem->mTimeStamp
较远(1s),此次acquireBuffer操作不会成功,并返回PRESENT_LATER
;
-
maxFrameNumber:表示acquireBuffer只获取frameNumber小于等于maxFrameNumber的Buffer,如果没有,返回
PRESENT_LATER
。
返回值
acquireBuffer操作成功时,返回NO_ERROR
;
操作失败时:
NO_BUFFER_AVAILABLE
:队列中没有可用Buffer;PRESENT_LATER
:Buffer相关参数不满足presentWhen和maxFrameNumber参数;INVALID_OPERATION
:无效操作,如超过最大ACQUIRED
Buffer数。
1.1、acquireBuffer触发过程
在BufferQueueProducer::queueBuffer
的最后,通过IConsumerListener::onFrameAvailable()
接口通知BufferQueueConsumer进行消费:
cpp
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
......
{ // scope for the lock
......
if (frameAvailableListener != nullptr) {
// IConsumerListener接口对象
frameAvailableListener->onFrameAvailable(item);
} else if (frameReplacedListener != nullptr) {
frameReplacedListener->onFrameReplaced(item);
}
}
......
return NO_ERROR;
}
这里frameAvailableListener
来源于mCore->mConsumerListener
,作为IConsumerListener
接口的具体对象,在BLASTBufferQueue对象创建时进行设置:
cpp
// frameworks/native/libs/gui/BufferQueueConsumer.cpp
status_t BufferQueueConsumer::connect(
const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
......
// 初始化mCore->mConsumerListener
mCore->mConsumerListener = consumerListener;
mCore->mConsumerControlledByApp = controlledByApp;
return NO_ERROR;
}
mCore->mConsumerListener
实际便是ConsumerBase对象,它实现了IConsumerListener
接口,并重写了onFrameAvailable()
方法:
cpp
// frameworks/native/libs/gui/ConsumerBase.cpp
void ConsumerBase::onFrameAvailable(const BufferItem& item) {
sp<FrameAvailableListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mFrameAvailableMutex);
listener = mFrameAvailableListener.promote();
}
if (listener != nullptr) {
listener->onFrameAvailable(item);
}
}
以上方法中,又将回调交给了mFrameAvailableListener,mFrameAvailableListener则是BLASTBufferQueue对象,它实现了ConsumerBase::FrameAvailableListener接口,因此,回调实际执行位置就是BLASTBufferQueue::onFrameAvailable()
方法,并从这里逐步开始Consumer的acquireBuffer
流程。从Producer到Consumer接收回调开始acquireBuffer这段过程时序图如下所示:
1.2、acquireBuffer()实现
BufferQueueConsumer::acquireBuffer()
方法:
cpp
// frameworks/native/libs/gui/BufferQueueConsumer.cpp
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
......
int numDroppedBuffers = 0;
sp<IProducerListener> listener;
{
......
bool sharedBufferAvailable = mCore->mSharedBufferMode &&
mCore->mAutoRefresh && mCore->mSharedBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT;
// 非Shared Buffer Mode模式下,如果mCore->mQueue为空,说明没有QUEUED状态的Buffer,
// 则直接返回NO_BUFFER_AVAILABLE
if (mCore->mQueue.empty() && !sharedBufferAvailable) {
return NO_BUFFER_AVAILABLE;
}
// 取出队列中的队头元素
BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
if (expectedPresent != 0 && !mCore->mQueue.empty()) {
// 针对expectedPresent参数的处理,略去
......
if (!bufferIsDue || !consumerIsReady) {
return PRESENT_LATER;
}
}
int slot = BufferQueueCore::INVALID_BUFFER_SLOT;
// SharedBufferMode相关流程,略去
if (sharedBufferAvailable && mCore->mQueue.empty()) {
......
} else if (acquireNonDroppableBuffer && front->mIsDroppable) {
return NO_BUFFER_AVAILABLE;
} else {
// 获得BufferSlot索引
slot = front->mSlot;
*outBuffer = *front;
}
// mIsStale为true表示处于mQueue中的BufferItem对应的Buffer被释放
if (!outBuffer->mIsStale) {
// 表示已执行acquireBuffer操作
mSlots[slot].mAcquireCalled = true;
// 设置Buffer状态
if (mCore->mQueue.empty()) {
// Shared Buffer Mode模式时,可以同时保持ACQUIRED和QUEUED状态
mSlots[slot].mBufferState.acquireNotInQueue();
} else {
// 由QUEUED状态变为ACQUIRED状态
mSlots[slot].mBufferState.acquire();
}
// 重置mSlots[slot]中的Fence对象
mSlots[slot].mFence = Fence::NO_FENCE;
}
......
// 从队列中移除
mCore->mQueue.erase(front);
// 唤醒mCore->mDequeueCondition
mCore->mDequeueCondition.notify_all();
}
......
return NO_ERROR;
}
以上方法中:
- 获取
mCore->mQueue
队头元素,并赋值给outBuffer返回; - 获取队头元素对应的Slot索引值,并将
mSlots[slot].mBufferState
状态由QUEUED
状态设置为ACQUIRED
; - 从
mCore->mQueue
中移除元素,实现"消费"。
再来看下执行完这个方法后,BLASTBufferQueue中是如何将buffer同步给surfaceflinger进行合成的:
cpp
// frameworks/native/libs/gui/BLASTBufferQueue.cpp
status_t BLASTBufferQueue::acquireNextBufferLocked(
const std::optional<SurfaceComposerClient::Transaction*> transaction) {
......
BufferItem bufferItem;
// 从Consumer中执行acquireBuffer流程,获取可用BufferItem
status_t status =
mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
// 获取GraphicBuffer
auto buffer = bufferItem.mGraphicBuffer;
// mNumFrameAvailable表示已经入队但没有被消费者acquire的Buffer个数
// 或者可以理解为已经处于QUEUED且未到ACQUIRED状态的Buffer个数
mNumFrameAvailable--;
// 验证buffer size
if (rejectBuffer(bufferItem)) {
mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
return acquireNextBufferLocked(transaction);
}
// mNumAcquired表示处于ACQUIRED状态的Buffer个数
mNumAcquired++;
mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
// 创建ReleaseCallbackId用于sf完成合成后向客户端回调进行释放buffer
ReleaseCallbackId releaseCallbackId(buffer->getId(), mLastAcquiredFrameNumber);
// mSubmitted映射表中保存已经提交sf的BufferItem,Key为releaseCallbackId,用于releaseBuffer
// 后释放对应的BufferItem
mSubmitted[releaseCallbackId] = bufferItem;
// consumer disconnect后的通知操作
bool needsDisconnect = false;
mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
if (needsDisconnect) {
t->notifyProducerDisconnect(mSurfaceControl);
}
// 更新buffer大小
if (mRequestedSize == getBufferSize(bufferItem) ||
bufferItem.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
mSize = mRequestedSize;
}
// 获取buffer裁剪区域
Rect crop = computeCrop(bufferItem);
// 设置releaseBuffer时的回调
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
// 向Transaction中设置buffer
t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, mProducerId,
releaseBufferCallback);
// 设置dataspace
t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
// 设置hdr元数据
t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
// 设置更新区域
t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
// 设置TransactionCompleted回调
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
// mUpdateDestinationFrame为true表示
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);
}
// 设置buffer的裁剪区域
t->setBufferCrop(mSurfaceControl, crop);
// 设置buffer方向
t->setTransform(mSurfaceControl, bufferItem.mTransform);
// 表示是否需要用屏幕空间的逆变换矩阵进行变换
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
// 设置Buffer是否可以自动更新属性(仅针对共享buffer)
t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
// 设置Buffer期望present时间
if (!bufferItem.mIsAutoTimestamp) {
t->setDesiredPresentTime(bufferItem.mTimestamp);
}
......
// 合并pending transaction
mergePendingTransactions(t, bufferItem.mFrameNumber);
if (applyTransaction) {
// 向SF提交事务
t->setApplyToken(mApplyToken).apply(false, true);
mAppliedLastTransaction = true;
mLastAppliedFrameNumber = bufferItem.mFrameNumber;
} else {
// 设置Buffer bairrer,t将返回给业务侧自行进行提交
t->setBufferHasBarrier(mSurfaceControl, mLastAppliedFrameNumber);
mAppliedLastTransaction = false;
}
return OK;
}
以上方法中,会将BBQ中的所有BufferItem数据通过SurfaceComposerClient::Transaction的各setXXX()
方法,提交给surfaceflinger进程。
这部分变化过程图示如下所示:
二、releaseBuffer操作
releaseBuffer操作用于释放GraphicBuffer,即将其所有权从Consumer中转移到BufferQueue中,并将其状态重新设置回FREE
状态。
arduino
// frameworks/native/include/gui/IGraphicBufferConsumer.h
virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display,
EGLSyncKHR fence, const sp<Fence>& releaseFence) = 0;
参数
-
frameNumber:帧序列,用于识别具体返回的buffer,在queueBuffer时,会为一个BufferItem设置frameNumber;
-
display:EGLDisplay对象
-
fence:releaseFence对象,用于DPU和GPU间Buffer使用状态的同步;当DPU中不再显示该帧Buffer时,releaseFence状态变为Signal,意味这GPU可以对其进行绘制。
返回值
-
操作成功时,返回
NO_ERROR
; -
操作失败时:
STALE_BUFFER_SLOT
:表示当前Buffer已经过期(进行了重申请),Consumer中必须释放所有对其的引用;BAD_VALUE
: 错误值,buffer slot错误、fence为空、bufferSlot状态不处于active状态。
2.1、releaseBuffer触发过程
当surfaceflinger中完成合成流程后,通过TransactionCallbackInvoker::sendCallbacks()
方法发起TransactionCompletedListener::onTransactionCompleted()
回调,通知应用进程完成当前帧的合成显示,同时上一帧的GraphicBuffer将会被释放。
TransactionCompletedListener::onTransactionCompleted()
中会依次处理onTransactionCommitted
、ReleaseBufferCallback
、onTransactionCompleted
事件的回调:
arduino
// frameworks/native/libs/gui/SurfaceComposerClient.cpp
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> callbacksMap;
std::multimap<int32_t, sp<JankDataListener>> jankListenersMap;
......
for (const auto& transactionStats : listenerStats.transactionStats) {
// handle on commit callbacks
for (auto callbackId : transactionStats.callbackIds) {
if (callbackId.type != CallbackId::Type::ON_COMMIT) {
continue;
}
.....
// 执行onTransactionCommitted回调
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
surfaceControlStats);
......
}
// handle on complete callbacks
for (auto callbackId : transactionStats.callbackIds) {
if (callbackId.type != CallbackId::Type::ON_COMPLETE) {
continue;
}
auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId];
std::vector<SurfaceControlStats> surfaceControlStats;
for (const auto& surfaceStats : transactionStats.surfaceStats) {
......
if (surfaceStats.previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) {
ReleaseBufferCallback callback;
// 执行releaseBufferCallback回调
if (callback) {
callback(surfaceStats.previousReleaseCallbackId,
surfaceStats.previousReleaseFence
? surfaceStats.previousReleaseFence
: Fence::NO_FENCE,
surfaceStats.currentMaxAcquiredBufferCount);
}
}
}
// 执行onTransactionCompleted回调
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
surfaceControlStats);
}
}
......
}
ReleaseBufferCallback这个可执行函数是BLASTBufferQueue::releaseBufferCallbackThunk()
方法,然后进入BBQ后逐步执行releaseBuffer流程,这个过程这里就不展开分析了,核心步骤时序图如下所示:

2.2、releaseBuffer()实现
BufferQueueConsumer::releaseBuffer()
方法如下:
ini
// frameworks/native/libs/gui/BufferQueueConsumer.cpp
status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
EGLSyncKHR eglFence) {
sp<IProducerListener> listener;
{ // Autolock scope
// 如果frameNumber不一致,说明进行过重新申请,该buffer已经过期,返回STALE_BUFFER_SLOT进行free操作
// mFrameNumber在queueBuffer期间赋值
if (frameNumber != mSlots[slot].mFrameNumber &&
!mSlots[slot].mBufferState.isShared()) {
return STALE_BUFFER_SLOT;
}
// release不处于ACQUIRED状态时,返回错误
if (!mSlots[slot].mBufferState.isAcquired()) {
return BAD_VALUE;
}
mSlots[slot].mEglDisplay = eglDisplay;
mSlots[slot].mEglFence = eglFence;
// 更新releaseFence给mSlots[slot].mFence,用于DPU/GPU信号同步
mSlots[slot].mFence = releaseFence;
// 退出ACQUIRED状态
mSlots[slot].mBufferState.release();
// 非shardBufferMode模式时,将对应BufferSlot从mCore->mActiveBuffers中移除,
// 并重新放入mCore->mFreeBuffers中,变为FREE状态
if (!mSlots[slot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(slot);
mCore->mFreeBuffers.push_back(slot);
}
if (mCore->mBufferReleasedCbEnabled) {
listener = mCore->mConnectedProducerListener;
}
// 唤醒mCore->mDequeueCondition
mCore->mDequeueCondition.notify_all();
} // Autolock scope
// 回调Producer接口通知Producer
if (listener != nullptr) {
listener->onBufferReleased();
}
return NO_ERROR;
}
以上方法中:
- 通过
mSlots[slot].mBufferState.release()
退出ACQUIRED
状态; - 从
mCore->mActiveBuffers
列表中移除,并添加到mCore->mFreeBuffers
列表。
通过这一步,BufferSlot又重新回到了mCore->mFreeBuffers
中,同时状态由ACQUIRED
恢复为FREE
状态。
这部分变化过程图示如下所示:
