BLASTBufferQueue03-BufferQueueConsumer核心操作

前言

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;
}

以上方法中:

  1. 获取mCore->mQueue队头元素,并赋值给outBuffer返回;
  2. 获取队头元素对应的Slot索引值,并将mSlots[slot].mBufferState状态由QUEUED状态设置为ACQUIRED
  3. 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()中会依次处理onTransactionCommittedReleaseBufferCallbackonTransactionCompleted事件的回调:

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;
}

以上方法中:

  1. 通过mSlots[slot].mBufferState.release()退出ACQUIRED状态;
  2. mCore->mActiveBuffers列表中移除,并添加到mCore->mFreeBuffers列表。

通过这一步,BufferSlot又重新回到了mCore->mFreeBuffers中,同时状态由ACQUIRED恢复为FREE状态。

这部分变化过程图示如下所示:

相关推荐
Kapaseker13 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952714 小时前
Andorid Google 登录接入文档
android
黄林晴16 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android
_小马快跑_1 天前
Kotlin | 从SparseArray、ArrayMap的set操作符看类型检查的不同
android