SurfaceFlinger系列02--BufferQueue和BufferQueueCore

相关文件:

frameworks\native\include\gui\BufferQueue.h

frameworks\native\include\gui\BufferQueueCore.h

frameworks\native\include\ui\BufferQueueDefs.h

 

顾名思义,BufferQueue是用来保存buffer的queue。Android显示系统中为此提供了两个类BufferQueue和BufferQueueCore,从名字上看两个类都是buffer queue相关,但后者似乎是更核心一些,下面来具体分析这两个类之间的关系。

BufferQueue

BufferQueue类一开始就定义了几个非常重要的关键属性值。

  • NUM_BUFFER_SLOTS:BufferQueue类定义了一个queue中能够保存的buffer的最大数量NUM_BUFFER_SLOTS,其数量为64,这是android::BufferQueueDefs命令空间中定义的一个静态常量NUM_BUFFER_SLOTS,因此无法在runtime过程中改变此值。
  • INVALID_BUFFER_SLOT:BufferSlot的默认状态,即此BufferSlot还未指向已经存在并且有效的buffer时的状态
  • NO_BUFFER_AVAILABLE:一般dequeueBuffer前要查询BufferQueue中是否有buffer可用,如果没有,则返回NO_BUFFER_AVAILABLE,表示当前BufferQueue中没有pending状态的buffer可用。
  • PRESENT_LATER:dequeueBuffer时,如果此时buffer还没有准备好,则返回PRESENT_LATER,表示此时dequeueBuffer太早了,等会再来dequeue。
  • MAX_MAX_ACQUIRED_BUFFERS:当处于异步模式时,系统要预留2个slot以保证producer和consumer之间的异步关系,因此该值等于NUM_BUFFER_SLOTS-2。

BufferQueue类中还定义了一个ProxyConsumerListener类,其继承关系如下图所示:

 从继承关系上看,ProxyConsumerListener类是一个Bn端(服务端)的监听类(从类名上看,似乎使用代理模式,这点待进一步研究)。ProxyConsumerListener类是ConsumerListener类的实现,主要用来保存一个指向真正的consumer object的weak引用。ProxyConsumerListener的主要目的是避免BufferQueue对象和consumer对象的循环引用。

class ProxyConsumerListener : public BnConsumerListener {
public:
    explicit ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
    ~ProxyConsumerListener() override;
    void onDisconnect() override;
    void onFrameAvailable(const BufferItem& item) override;
    void onFrameReplaced(const BufferItem& item) override;
    void onBuffersReleased() override;
    void onSidebandStreamChanged() override;
    void addAndGetFrameTimestamps(
            const NewFrameEventsEntry* newTimestamps,
            FrameEventHistoryDelta* outDelta) override;
private:
    // mConsumerListener is a weak reference to the IConsumerListener.  This is
    // the raison d'etre of ProxyConsumerListener.
    wp<ConsumerListener> mConsumerListener;
};

ProxyConsumerListener的使用在ConsumerBase类。

ProxyConsumerListener的实现比较简单,几个函数的功能如下表所示,显然主要是监听一些动作,当这些对应的事件发生后,及时通知另一端。这里显然做数据同步的功能,具体同步的肯定是producer和consumer两端的关系,这一部分内容待补充。

成员函数

功能描述

onDisconnect

通知远端已经断开链接了

onFrameAvailable

通知远端frame已经准备好了

onFrameReplaced

通知远端frame被替换了

onBuffersReleased

通知远端buffer已经release了

onSidebandStreamChanged

 

addAndGetFrameTimestamps

 

看完ProxyConsumerListener类,BufferQueu就剩下最后一个成员了,也是最重要的一个成员:createBufferQueue函数。

static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger = false);

显然,这个函数是用来创建buffer queue的,其入参即buffer queue的producer和consumer,最后一个参数指明consumer是否为SurfaceFlinger。该函数的使用有两个地方,一个一个在BufferLayer::onFirstRef函数中,一个在SurfaceFlinger:: processDisplayChangesLocked函数中,这里暂时只讲BufferLayer::onFirstRef里面的使用。该函数似乎是给外接屏使用的,这里暂时不深入。

void BufferLayer::onFirstRef() {
    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    BufferQueue::createBufferQueue(&producer, &consumer, true);
    mProducer = new MonitoredProducer(producer, mFlinger, this);
    mConsumer = new BufferLayerConsumer(consumer,
            mFlinger->getRenderEngine(), mTextureName, this);
    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
    mConsumer->setContentsChangedListener(this);
    mConsumer->setName(mName);

    if (mFlinger->isLayerTripleBufferingDisabled()) {
        mProducer->setMaxDequeuedBufferCount(2);
    }

    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
    updateTransformHint(hw);
}

 

BufferLayer::onFirstRef是在上层应用请求SurfaceFlinger创建Layer时调用的,即应用告诉SurfaceFlinger它要创建一个Layer(即APP端的窗口、Native层的Surface),此时SurfaceFlinger就会创建创建对应Layer,并为此Layer创建一个对应的BufferQueue,即应用的一个窗口对应一个BufferQueue。那么显然,这里的producer是指应用端对应的窗口,consumer即指SurfaceFlinger(第三个参数指定的)。BufferLayer::onFirstRef函数这里不深入研究。

继续看createBufferQueue函数的源代码,删除次要的代码,其主要代码部分如下:

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

首先,他调用BufferQueueCore的构建函数创建了一个core对象,显然这是在说,BufferQueueCore才是buffer queue的核心,真正干活的其实是BufferQueueCore这个类,BufferQueue只是个外壳而已。其次分别创建了producer和consumer对象,返回给了对应的Layer,然后BufferLayer将这两个添加了其内部的Consuerm Listener监听器中,这样创建出来的layer就可以与SurfaceFlinger之间进行相关的数据互动操作了,这里不在深入具体细节,后续专门介绍。

BufferQueueCore

 

从前面的分析可以看到,BufferQueue类其实只做了一件事情:创建BufferQueueCore。其他什么事情都没做。那么这个BufferQueueCore肯定是非常重要的了。接下来看BufferQueueCore这个类。

        BufferQueueCore没有复杂的继承关系,直接继承了RefBase类。

        BufferQueueCore定义了当前queue的状态:

  • CURRENTLY_CONNECTED_API:值为-1,表示当前有producer连接到buffer queue
  • NO_CONNECTED_API:值为0,表示当前没有producer连接到buffer queue

BufferQueueCore

 

成员变量

描述

mMutex

被mutable修饰,表明此锁的状态是随时变化的

mIsAbandoned

该变量表示buffer queue已经不在继续消费push到其中的image buffer数据,初始化时默认为false,当consumerDisconnect时,被设置成true。

mConsumerControlledByApp

表示已经连接的consumer是否被application所控制

mConsumerName

该buffer queue对应的consumer的名字,用于在log中标识buffer queue的所有者

mConsumerListener

用于向已连接的consumer发送通知消息。默认初始化时为NULL,当consumerConnect或consumerDisconnect时写入有效值。

mConsumerUsageBits

包含了consumer想要的flags信息

mConsumerIsProtected

表示conumser是否准备处理受保护的buffer

mConnectedApi

表示当前连接到buffer queue的producer API,默认为NO_CONNECTED_API,当connect或disconnect时会发生变化

mConnectedPid

最后一个成功连接到该buffer queue的进程的pid

mConnectedProducerListener

该监听器用于处理onBufferRelease通知消息

mSlots

即BufferSlot数组,最大保存NUM_BUFFER_SLOTS个BufferSlot。 mSlots必须与producer侧成镜像状态,这使buffer的所有权在producer和consumer之间进行转换时,可以不用通过Binder来发送GraphicBuffer就能实现。整个数组在初始化时被设置为NULL,当requestBuffer时,才会为slot分配buffer。

mFreeSlots

set<int>类型变量,包含所有处于FREE状态的slot序号,这些slot当前并没有与某个buffer关联起来,完全处于FREE状态。

mFreeBuffers

list<int>类型变量,包含当前所有处于FREE状态的slot,但是这些slot都已经被关联到了特定的buffer。

mUnusedSlots

list<int>类型变量,表示当前所有没有被使用的slot,这些slot都是FREE状态,也没有与buffer相关联。

mActiveBuffers

set<int>类型变量,包含当前所有与非FREE状态Buffer关联的slot

mQueue

Vector<BufferItem>类型变量,同步模式中使用的FIFO队列

mDequeueCondition

在同时模式中,供dequeueBuffer方法使用的一个条件变量

mDequeueBufferCannotBlock

表示dequeueBuffer操作是否可以被block。这个标志在producer和consumer被Application所控制的情况下,做connect操作时设置。

mDefaultBufferFormat

buffer format的默认格式,如果dequeueBuffer时没有指定buffer format,则使用此变量所设置的format

mDefaultWidth

所分配的buffer的默认宽度,在dequeueBuffer中使用,默认为0

mDefaultHeight

所分配的buffer的默认高度,在dequeueBuffer中使用,默认为0

mDefaultBufferDataSpace

queueBuffer时,如果指定DATA_DATASPACE_UNKNOWN了,则使用此值

mMaxBufferCount

指定一次最大分配的buffer数量,可以由consumer进行设置

mMaxAcquiredBufferCount

指定consumer端一次最大acquire的buffer数量,默认为1.consumer端可以通过调用setMaxAcquiredBufferCount来改变此值,但也仅限在尚有producer连接到buffer queue时生效,This value is used to derive the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer.

mMaxDequeuedBufferCount

producer端一次最大dequeue的buffer数量,默认为1,producer端可以通过setMaxDequeuedBufferCount函数修改此值。

mBufferHasBeenQueued

当一个buffer被queue进buffer queue时,会将此值设置为true。当因某种原因使得所有buffer都被free时,此值会被重置。

mFrameCounter

每当queueBuffer或buffer allocation成功时,这个值都会增长

mTransformHint

用于优化屏幕旋转

mSidebandStream

a handle to the sideband buffer stream

mIsAllocating

表示一个producer是否正在分配buffers,当该变量值为true时,producer不应该修改任何FREE状态的slot。当此变量值变成false时,mIsAllocatingCondition会被signaled,表明producer已经分配完buffer。

mIsAllocatingCondition

与mIsAllocating配合使用

mAllowAllocation

用来决定dequeueBuffer操作时是否可以分配新的buffer

mBufferAge

tracks the age of the contents of the most recently dequeued buffer as the number of frames that have elapsed since it was last queued

mGenerationNumber

stores the current generation number of the attached producer. Any attempt to attach a buffer with a different generation number will fail.

mAsyncMode

指示异步模式是否被开启。在异步模式中,需要分配额外的buffer以保证producer在enqueue buffer时不被blocking。

mSharedBufferMode

indicates whether or not shared buffer mode is enabled.

mAutoRefresh

若为enabled,表示即使BufferQueue没有通知buffer已经准备好了,consumer也应该自动acquire buffer,

mSharedBufferSlot

当sharedBufferMode开启后,该变量用来跟踪哪个slot包含了shared buffer。

mLastQueuedSlot

最后一次被queue的buffer的序号

mUniqueId

唯一的标识ID

mSharedBufferCache

shared buffer的Cached data

 

posted @ 2019-01-17 22:32  TPrime.A  阅读(3198)  评论(0编辑  收藏  举报