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状态。

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

相关推荐
还是奇怪6 小时前
Linux - 安全排查 3
android·linux·安全
Android采码蜂6 小时前
BLASTBufferQueue02-BufferQueueProducer核心操作
android
2501_915921437 小时前
没有Mac如何完成iOS 上架:iOS App 上架App Store流程
android·ios·小程序·https·uni-app·iphone·webview
码农明明7 小时前
Google Play 应用上架二三事
android·google
红橙Darren10 小时前
手写操作系统 - 环境搭建
android·微信·操作系统
_一条咸鱼_10 小时前
Android Runtime直接内存管理原理深度剖析(73)
android·面试·android jetpack
你听得到1110 小时前
揭秘Flutter图片编辑器核心技术:从状态驱动架构到高保真图像处理
android·前端·flutter
wilinz10 小时前
Flutter Android 端接入百度地图踩坑记录
android·flutter
小袁拒绝摆烂13 小时前
SQL开窗函数
android·sql·性能优化