美文网首页
BufferQueue学习

BufferQueue学习

作者: 欣兄 | 来源:发表于2021-05-20 16:38 被阅读0次

    上一篇说完App申请完vsync后要进行绘制,本来要说一下绘制的过程,但是感觉进度有点慢,主要研究sf,所以转换下学习思路。

    一、BufferQueue基本概念:

    BufferQueue的核心逻辑是生产者消费者逻辑又是GraphicBuffer管理者,在BufferQueue这个生产者消费者框架中, BufferQueuecore可以理解为数据缓冲区的管理者,代码逻辑在BufferQueue.cpp和BufferQueuecore.cpp中。它的消费者是BufferQueueConsumer,生产者是BufferQueueProducer。
    先看一张比较权威的BufferQueue相关基本操作流程,

    image

    首先初始状态下,所有可用BufferSlot全是FREE状态,在mFreeSlots中管理。

    • Producer 从 BufferQueue中dequeue一个FREE BufferSlot, Dequeue成功后,BufferSlot状态从FREE变为DEQUEUED;
    • Producer端填充好BufferSlot数据后,queue到BufferQueue中,BufferSlot状态从DEQUEUED变为QUEUED,且调用消费者onFrameAvailable通知它有可消费的BufferSlot;
    • Consumer从BufferQueue中acquire一个有数据的BufferSlot,BufferSlot状态从QUEUED变为ACQUIRED;
    • Consumer 使用完BufferSlot后,BufferSlot状态从ACQUIRED变为FREE
      总结一下BufferSlot的5种状态:FREE、DEQUEUED、QUEUED、ACQUIRED、SHARED。

    从源码中看下buffer状态改变原理

    /frameworks/native/include/gui/BufferSlot.h
     A buffer can be in one of five states, represented as below:
        
                 | mShared | mDequeueCount | mQueueCount | mAcquireCount |
         --------|---------|---------------|-------------|---------------|
         FREE    |  false  |       0       |      0      |       0       |
         DEQUEUED|  false  |       1       |      0      |       0       |
         QUEUED  |  false  |       0       |      1      |       0       |
         ACQUIRED|  false  |       0       |      0      |       1       |
         SHARED  |  true   |      any      |     any     |      any      |
    

    举例一个mQueueCount变化

        inline bool isQueued const {
            return  mQueueCount> 0;
        }
    
        inline void queue() {
           if (mDequeueCount > 0) {
               mDequeueCount--;
           }
           mQueueCount++;
       }
    

    queue()方法调用后,mQueueCount++,isQueued() 方法返回值当然就为true;
    可以明显的看到 buffer的状态由引用计数来表示。

    二、BufferQueue内部结构

    /frameworks/native/libs/gui/BufferQueue.cpp
    void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
            sp<IGraphicBufferConsumer>* outConsumer,
            bool consumerIsSurfaceFlinger) {
    
        sp<BufferQueueCore> core(new BufferQueueCore());
        sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
        sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
        *outProducer = producer;
        *outConsumer = consumer;
    }
    

    通过其createBufferQueue方法可以看到会创建
    BufferQueueCore、BufferQueueProducer、BufferQueueConsumer。
    BufferQueueCore 负责维护 BufferQueue 的基本数据结构,而 BufferQueueProducer 和 BufferQueueConsumer 则负责提供操作 BufferQueue 的基本接口。

    三、BufferSlot和BufferItem详解

    1、BufferSlot和GraphicBuffer关联

    BufferQueueCore中管理着数据缓冲区,而数据的核心GraphicBuffer关联在BufferSlot中。

    /frameworks/native/include/gui/BufferQueueCore.h
    class BufferQueueCore : public virtual RefBase {
    ......
        BufferQueueDefs::SlotsType mSlots;
    }  @1
    
    /frameworks/native/libs/gui/include/gui/BufferQueueDefs.h
    namespace BufferQueueDefs {
       Typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
    } @2
    
    /frameworks/native/libs/gui/include/gui/BufferSlot.h
    struct BufferSlot {
         sp<GraphicBuffer> mGraphicBuffer;
    }  @3
    

    由@1知BufferQueueCore定义了BufferQueueDefs::SlotsType mSlots,
    由@2知mSlots实际上是一个BufferSolt的数组。
    由@3知 BufferSolt中定义了一个GraphicBuffer的強指针用于关联mGraphicBuffer。
    这样BufferSlot 和 GraphicBuffer 就关联上了。

    2、BuffetItem关联BufferSlot

    BufferQueue框架中,消费者和生产者对缓冲区数据操作的单元核心就是一个BufferSlot,也就是取GraphicBuffer,放GraphicBuffer的操作其实是针对BufferSlot来完成的。

    /frameworks/native/libs/gui/include/gui/BufferQueueCore.h
    class BufferQueueCore : public virtual RefBase {
        ......
    typedef Vector<BufferItem> Fifo;
    ......
      Fifo mQueue;
    }
    
    /frameworks/native/libs/gui/include/gui/BufferItem.h
    class BufferItem:public Flattenable<BufferItem>{
        //mSlot is the slot idex of this buffer(default INVALID_BUFFER_SLOT)
        Int mSlot;
    }
    
    • BufferSlot 的存和取是在BufferQueueCore中定义了Fifo mQueue,Fifo是向量集,里面存的是BufferItem,而 BufferItem中又定义了mSlot的索引值。这样就可以和BufferSlot关联上了,可以在dequeue,queue,acquire方法中看出其关系。
    • 生产者从mQueue上获取BufferItem从而找到了对应的BufferSlot,并对它完成一系列的操作之后,放回到mQueue中供消费者使用,消费者也是从mQueue上获取BufferItem从而找到对应的BufferSlot来消费,消费完成之后放回mQueue。不过需要注意实际上不是真正的把BufferSlot取出放回mQueue,而是mSlots索引值的传递过程。

    3、BufferSlot状态说明

    image.png

    说明:
    mSlots BufferSlot结构体数组,数组长度为64

    • mFreeSlots BufferSlot状态为FREE,且没有GraphicBuffer与之相绑定的slot集合
    • mFreeBuffers BufferSlot状态为FREE,且有GraphicBuffer与之相绑定的slot集合
    • mActiveBuffers BufferSlot状态不为FREE(即DEQUEUED、QUEUED、ACQUIRED、SHARED)的slot集合。既然状态不是FREE,那么该BufferSlot必然有一个GraphicBuffer与之相绑定
    • mUnusedSlots 未参与使用的slot集合,由 mMaxBufferCount 决定
    • mSlots = mFreeSlots + mFreeBuffers + mActiveBuffers + mUnusedSlots

    四、BufferQueue生产者和消费者详解

    我们知道 一个widow对应一个layer,一个layer对应一个生产者消费者模型。
    BufferQueueConsumer 和 BufferQueueProducer 分别对应文件BufferQueueConsumer.cpp 和 BufferQueueProducer.cpp 和 BufferQueueCore.cpp 在同级目录都在/frameworks/native/libs/gui目录下。

    1、两个类的继承关系和重要函数:

    BuffeQueueProducer继承关系:

    (BufferQueueProducer.h) BufferQueueProducer : public BnGraphicBufferProducer,private IBinder::DeathRecipient
    
    (IGraphicBufferProducer.h)BnGraphicBufferProducer : public BnInterface<IGraphicBufferProducer>
    
    (IInterface.h)class BnInterface : public INTERFACE, public BBinder
    

    可以看到BufferQueueProducer继承了BnGraphicBufferProducer而BnGraphicBufferProducer又继承了IGraphicBufferProducer和BnInterface ,来完成主要的BufferSlot的流转操作,也提供了远程代理接口,实现跨进程binder调用。
    同时BufferQueueProducer还继承了DeathRecipient 用来处理Binder死亡通知。

    BuffeQueueProducer关键方法:

    • requestBuffer 获取对应BufferSlot的GraphicBuffer地址。
    • setMaxDequeuedBufferCount 设置最大同时可以dequeue出来的的BufferSlot数量。
    • dequeueBuffer 从FREE状态下的BufferSlots中队列中获取空闲的BufferSlot做生产使用,优先从mFreeBuffers中获取,如果没有则从mFreeSlots中获取。
    • attachBuffer 绑定已经分配好的GraphicBuffer到FREE状态下的BufferSlot中,优先从- mFreeSlots中查找BufferSlot,如果没有则从mFreeBuffers中查找并绑定。
    • queueBuffer 生产者把生产好的BufferSlot放到队列中供消费者使用。
    • detachBuffer 把attachBuffer了GraphicBuffer的 Active状态下的BufferSlot的放到mFreeBuffers之后直接取消GraphicBuffer的绑定。
    • detachNextBuffer 把需要释放的BufferSlot中的GraphicBuffer指针赋值到outBuffer输出之后,把BufferSlot的放到mFreeBuffers并解绑定GraphicBuffer。
    • cancelBuffer 把BufferSlot放回到mfreeBuffers中,不会释放graphicbuffer。
    • connect 生产者通过该接口把IProducerListener注册到BufferQueueCore中供消费者回调,同时建立了Binder死亡通知通路。
    • disconnect断开BufferQueueProducer和BufferQueueCore之间建立的链接关系。

    BufferQueueConsumer继承关系:

    (BufferQueueConsumer.h) BufferQueueConsumer : public BnGraphicBufferConsumer 
    
    (IGraphicBufferConsumer.h)BnGraphicBufferConsumer : public SafeBnInterface<IGraphicBufferConsumer>
    
    (SafeInterface.h)SafeBnInterface:public BnInterface<Interface>
    

    可以看到BufferQueueConsumer的实现结构和BufferQueueProducer很相似继承了BnGraphicBufferConsumer 而BnGraphicBufferConsumer又最终继承了IGraphicBufferConsumer和SafeBnInterface,来完成主要的BufferSlot的流转操作,也提供了远程代理接口,实现跨进程binder调用。

    BufferQueueConsumer关键方法:

    • acquireBuffer 获取QUEUE状态下的BufferSlot进行消费。
    • releaseBuffer消费完成之后把BufferSlot放回mFreeBuffers队列中。
    • attachBuffer 把消费者的GraphicBuffer绑定到BufferSlot上使用。
    • detachBuffer把消费者的GraphicBuffer从BufferSlot上解绑。
    • setMaxBufferCount 设置最大可用BufferSlot数量。
    • setMaxAcquiredBufferCount 设置最大同时可以acquire的BufferSlot数量。
    • connect 建立消费者和BufferQueueCore之间的链接,注册IConsumerListener回调。
    • disconnect 销毁消费者和BufferQueue之间的链接。

    2、BufferQueueConsumer关键流程分析

    (1). acquirebuffer的流程

    主要流程是首先判断acquireBuffers是否已经超过最大一次能够Acquire的数量,mQueue是否为空,然后从mQueue中获取迭代器的第一个元素赋值给outBuffer输出,同时把mBufferState状态改为Acquired 并从mQueue中移除

    status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
            nsecs_t expectedPresent, uint64_t maxFrameNumber) {
        ...
        {
            //判断AcquireBuffers是否已经超过最大一次能够Acquire的数量。
            if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
                return INVALID_OPERATION;
            }
            //判断mQueue队列是否为空
            if (mCore->mQueue.empty() && !sharedBufferAvailable) {
                return NO_BUFFER_AVAILABLE;
            }
            //mCore->mQueue.begin()返回iterator,指向第一个元素赋值给front
            BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
            if (sharedBufferAvailable && mCore->mQueue.empty()) {//共享buffer的处理逻辑
              ...
            } else {//正常非共享模式下的逻辑
                slot = front->mSlot;    //从front获取对应的slot,front是一个BufferItem指针
                *outBuffer = *front;    //把front指向的BufferItem赋值给outBuffer,outBuffer就是要的buffer
            }
     
            if (!outBuffer->mIsStale) {
                mSlots[slot].mAcquireCalled = true;
                if (mCore->mQueue.empty()) {
                    mSlots[slot].mBufferState.acquireNotInQueue();
                } else {
                    mSlots[slot].mBufferState.acquire();     //把BufferState修改成acquired状态
                }
            }
     
            mCore->mQueue.erase(front);       //把acquired slot 对应的BufferItem从mQueue中移除。
            mCore->mDequeueCondition.notify_all();
        }
        return NO_ERROR;
    }
    

    (2). releasebuffer的流程

    releasebuffer主要流程是先做slot frameNumber 以及 BufferState有效性检查,修改mBufferState状态成FREE状态。然后把对应的slot从mActiveBuffers中移除并放回mFreeBuffers的过程。
    这个过程中不做GraphicBuffer和BufferSlot的解绑定操作,也就是说GraphicBuffer不会被释放。

    status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
            const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
            EGLSyncKHR eglFence) {
        //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;
        {
            //判断frameNumber是否有效,如果做过reallocated frameNumber将会改变。
            //这个frameNumber是什么?
            if (frameNumber != mSlots[slot].mFrameNumber &&
                    !mSlots[slot].mBufferState.isShared()) {
                return STALE_BUFFER_SLOT;
            }
            //判断BufferState是否是acquired状态
            if (!mSlots[slot].mBufferState.isAcquired()) {
                return BAD_VALUE;
            }
            mSlots[slot].mBufferState.release();   //调用mBufferState.release()将acqiure状态释放。
            if (!mSlots[slot].mBufferState.isShared()) {
                mCore->mActiveBuffers.erase(slot);   //将slot从mActiveBuffers中移除
                mCore->mFreeBuffers.push_back(slot); //将slot放入到mFreeBuffers队列中
            }
            listener = mCore->mConnectedProducerListener;  //获取ProducerListener
            mCore->mDequeueCondition.notify_all();
        }
        if (listener != nullptr) {
            listener->onBufferReleased();  //调用Producer的onBufferReleased回调通知Producer完成释放。
        }
     
        return NO_ERROR;
    }
    

    3、BufferQueueProducer关键流程分析

    (1). dequeuebuffer的流程

    dequeuebuffer是生产者端从BufferQueueCore上获取一个GraphicBuffer进行生产的过程,生产者BufferQueueProducer 会在去获取一个FREE状态的的BufferSlot。
    同时把mBufferState状态修改成Dequeue状态,把BufferSlot放到mActiveBuffers中管理。也由此可见GraphicBuffer是在这里实际创建的。

    status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
                                                uint32_t width, uint32_t height, PixelFormat format,
                                                uint64_t usage, uint64_t* outBufferAge,
                                                FrameEventHistoryDelta* outTimestamps) {
        
            int found = BufferItem::INVALID_BUFFER_SLOT;
            //调用waitForFreeSlotThenRelock 找到可以dequeue的 FREE状态下的BufferSlot
            while (found == BufferItem::INVALID_BUFFER_SLOT) {
                status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
            }
            const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); //把获取到的mGraphicBuffer地址赋值给buffer。
            if (mCore->mSharedBufferSlot != found) {
                mCore->mActiveBuffers.insert(found);   //把找到的slot放到mActiveBuffers中管理
            }
            *outSlot = found;  //赋值给outSlot输出
            mSlots[found].mBufferState.dequeue();  //修改BufferState 状态成dequeue状态。
        }
     
        return returnFlags;
    }
    

    FREE状态的BufferSlot又包含了mFreeSlots和mFreebuffers两组slots,dequeue的时候会先从mFreebuffers查找如果有可用的就使用,如果没有就从mFreeSlots获取BufferSlot并分配GraphicBuffer。
    这个过程在waitForFreeSlotThenRelock中实现
    下面是waitForFreeSlotThenRelock的流程:

    status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
            std::unique_lock<std::mutex>& lock, int* found) const {
        auto callerString = (caller == FreeSlotCaller::Dequeue) ?
                "dequeueBuffer" : "attachBuffer";
        bool tryAgain = true;
        while (tryAgain) {
     
                if (){
                } else {
                    if (caller == FreeSlotCaller::Dequeue) {   //Dequeuebuffer调用这段代码,先调用getFreeBufferLocked从mFreeBuffers中获取,如果找到了就返回。
                        // If we're calling this from dequeue, prefer free buffers
                        int slot = getFreeBufferLocked();
                        if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
                            *found = slot;
                        } else if (mCore->mAllowAllocation) {      // 如果没找到,在调用getFreeSlotLocked从mFreeSlots中获取。
                            *found = getFreeSlotLocked();
                        }
                    } else {
                        // If we're calling this from attach, prefer free slots
                        int slot = getFreeSlotLocked();         //attachbuffer调用这段代码,优先先调用getFreeSlotLocked从mFreeSlots中获取,如果找到了就返回。
                        if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
                            *found = slot;
                        } else {
                            *found = getFreeBufferLocked();    如果没找到,在调用getFreeBufferLocked从mFreeBuffers中获取。
                        }
                    }
                }
            }
        }
     
        return NO_ERROR;
    }
    
    int BufferQueueProducer::getFreeSlotLocked() const {
        if (mCore->mFreeSlots.empty()) {
            return BufferQueueCore::INVALID_BUFFER_SLOT;
        }
        int slot = *(mCore->mFreeSlots.begin());
        mCore->mFreeSlots.erase(slot);
        return slot;
    }
    

    (2). attachbuffer的流程

    如上面的waitForFreeSlotThenRelock流程,attachBuffer也是从FREE状态的slots上获取BufferSlot,但是和dequeueBuffer不同attachBuffer是优先从mfreeslots上获取,如果mfreeslots没有,再从mfreebuffers上获取。
    waitForFreeSlotThenRelock获取到BufferSlot之后,再把已有的申请好的GraphicBuffer绑定到这个BufferSlot上。同时把mBufferState状态修改成Dequeued状态。把BufferSlot放到mActiveBuffers中管理。

    status_t BufferQueueProducer::attachBuffer(int* outSlot,
            const sp<android::GraphicBuffer>& buffer) {
     
        //调用waitForFreeSlotThenRelock 找到可以FREE状态下的BufferSlot
        status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, lock, &found);
      
        *outSlot = found; //把找到的slot赋值给outSlot
        mSlots[*outSlot].mGraphicBuffer = buffer;  //把准备好的buffer关联到slot的mGraphicBuffer上
        mSlots[*outSlot].mBufferState.attachProducer(); // 修改BufferState成Dequued状态
      
        mCore->mActiveBuffers.insert(found);            // 把slot放到mActiveBuffers中管理。
        return returnFlags;
    }
    

    (3). queuebuffer的流程

    queuebuffer是生产者完成对GraphicBuffer的处理之后调用queuebuffer把GraphicBuffer放回mQueue的操作,同时把mBufferState修改成QUEUE状态。

    status_t BufferQueueProducer::queueBuffer(int slot,
            const QueueBufferInput &input, QueueBufferOutput *output) {
     
        sp<IConsumerListener> frameAvailableListener;
        sp<IConsumerListener> frameReplacedListener;
     
        BufferItem item;
        { // Autolock scope
      
            mSlots[slot].mBufferState.queue();  //修改mBufferState状态为QUEUE状态。
     
            //增加mFrameCounter
            ++mCore->mFrameCounter;
            currentFrameNumber = mCore->mFrameCounter;
            mSlots[slot].mFrameNumber = currentFrameNumber;
     
            //给BufferItem赋值
            item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
            item.mSlot = slot;
     
            output->bufferReplaced = false;
            if (mCore->mQueue.empty()) { //如果mQueue为空,就直接把BufferItem push到mQueue尾部。
                mCore->mQueue.push_back(item);
                frameAvailableListener = mCore->mConsumerListener;
            } else {  //如mQueue不为空,需要判断一下last BufferItem是否被替换,如果可以替换就替换,如果不可以替换就直接把BufferItem放到mQueue尾部。
                const BufferItem& last = mCore->mQueue.itemAt(
                        mCore->mQueue.size() - 1);
                if (last.mIsDroppable) {
     
                    if (!last.mIsStale) {
                        mSlots[last.mSlot].mBufferState.freeQueued();
     
                        // Don't put the shared buffer on the free list.
                        if (!mSlots[last.mSlot].mBufferState.isShared()) {
                            mCore->mActiveBuffers.erase(last.mSlot);
                            mCore->mFreeBuffers.push_back(last.mSlot);
                            output->bufferReplaced = true;
                        }
                    }
     
                    mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
                    frameReplacedListener = mCore->mConsumerListener;
                } else {
                    mCore->mQueue.push_back(item);
                    frameAvailableListener = mCore->mConsumerListener;
                }
            }
            if (frameAvailableListener != nullptr) {
                frameAvailableListener->onFrameAvailable(item);   //调用消费者的onFrameAvailable通知消费者,有queue状态的BufferSlot可以使用。
            } else if (frameReplacedListener != nullptr) {
                frameReplacedListener->onFrameReplaced(item);     //调用消费者的onFrameReplaced通知消费者,有queue状态的BufferSlot可以被替换。
            }
        } // Autolock scope
     
        return NO_ERROR;
    }
    

    (4). detachBuffer的流程

    detachBuffer主要是对应生产者端的attachbuffer操作,将attachbuffer之后的BufferSlot,放回到mFreeSlots中,并解除对GraphicBuffer的绑定,并通知消费者Buffer释放。

    status_t BufferQueueProducer::detachBuffer(int slot) {
     
        sp<IConsumerListener> listener;
        
            mSlots[slot].mBufferState.detachProducer();  //修改BufferState的Dequeued状态成FREE状态
            mCore->mActiveBuffers.erase(slot);           //把slot从mActiveBuffers中移除
            mCore->mFreeSlots.insert(slot);              //把slot加到mFreeSlots中。
            mCore->clearBufferSlotLocked(slot);          //清除slot和Graphicbuffer的绑定关系。
            mCore->mDequeueCondition.notify_all();
            listener = mCore->mConsumerListener;   //把消费者回调的listener赋值给listener
        }
     
        if (listener != nullptr) {
            listener->onBuffersReleased();//调用消费者的listener接口通知消费者Buffer释放
        }
     
        return NO_ERROR;
    }
    

    五、总结

    BufferQueue的生产消费和BufferSlot状态关系用一张图总结下:


    image.png

    相关文章

      网友评论

          本文标题:BufferQueue学习

          本文链接:https://www.haomeiwen.com/subject/mfhbjltx.html