BufferQueue分析:Buffer队列

Buffer队列的创建

从Suface创建流程中分析可以,创建每一个Layer的时候,在Layer初始化的时候会为当前Layer创建一个BufferQueue队列,用于App端的Surface和SurfaceFlinger端的Layer间图像传递。

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

这段代码在Surface创建流程中已经分析过了
1:BufferQueue创建了一个的生产者和一个消费者
2:生产者被封装到了MonitoredProducer中,传递了App端,由Surface持有其代理
3:消费这被封装到了SurfaceFlingerComsumer中,设置Layer为内容变换监听者,当有新的Buffer到来,Layer进行处理。

先看下如何创建Buffer队列

    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    BufferQueue::createBufferQueue(&producer, &consumer);

初始化一个producer指针和一个consumer指针作为出参给创建BufferQueue的函数。创建好BufferQueue之后,会将BufferQueue的生产者和消费者分别保存在这两个变量中。

void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
        sp<IGraphicBufferConsumer>* outConsumer,
        const sp<IGraphicBufferAlloc>& allocator) {
    //创建一个BufferQueueCore对象
    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
    //创建一个BufferQueueProducer
    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
    //创建一个BufferQueueConsumer
    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));

    //将创建的producer和consumer分别保存在出参中
    *outProducer = producer;
    *outConsumer = consumer;
}

createBufferQueue是BufferQueue的静态函数,该函数中首先创建了一个BufferQueueCore对象,然后再以该对象作为参数创建了BufferQueueProducer和BufferQueueConsumer。

BufferQueueCore定义

class BufferQueueCore : public virtual RefBase {
    friend class BufferQueueProducer;
    friend class BufferQueueConsumer;

public:
  
    typedef Vector<BufferItem> Fifo;


private:
    sp<IGraphicBufferAlloc> mAllocator;

    // mMutex 用于同步producer和consumer对BufferQueueCore中变量的访问
    mutable Mutex mMutex;

    // mIsAbandoned 表示BufferQueue是否还能处理生产者传递的图像
    bool mIsAbandoned;

    // mConsumerName 用来在日志中表示唯一的BufferQueue
    String8 mConsumerName;

    // mConsumerListener 用于通知已经连接的Consumer有新Buffer到来
    sp<IConsumerListener> mConsumerListener;

    // mConnectedApi 表示生产者是否已经连接到BufferQueue
    int mConnectedApi;

    // mConnectedProducerToken 用于通知生产者BufferQueue是否已经死亡
    sp<IProducerListener> mConnectedProducerListener;

    // mSlots 是一个大小为64的bufferSlot数组,每个BufferSlot描述了一个GraphicBuffer与其相关的属性
    BufferQueueDefs::SlotsType mSlots;

    // mQueue is a FIFO of queued buffers used in synchronous mode.
    Fifo mQueue;

    // mFreeSlots 表示所有的FREE状态的BufferSlot, 这个BufferSlot还没有分配GraphicBuffer缓冲区
    std::set<int> mFreeSlots;

    // mFreeBuffers 表示所有的FREE状态的BufferSlot, 这个BufferSlot已经分配了GraphicBuffer缓冲区
    std::list<int> mFreeBuffers;

    // mUnusedSlots contains all slots that are currently unused. They should be
    // free and not have a buffer attached.
    std::list<int> mUnusedSlots;

    // mActiveBuffers 所有包含有使用状态GraphicBuffer的slot.
    std::set<int> mActiveBuffers;

    // mDequeueCondition 用于dequeuebuffer的同步
    mutable Condition mDequeueCondition;


    // mDefaultBufferFormat BufferQueue分配的GraphicBuffer的默认format
    PixelFormat mDefaultBufferFormat;

    // mDefaultWidth BufferQueue分配的GraphicBuffer的默认width
    uint32_t mDefaultWidth;

    // mDefaultHeight BufferQueue分配的GraphicBuffer的默认height
    uint32_t mDefaultHeight;

    // mDefaultBufferDataSpace BufferQueue分配的GraphicBuffer的默认DataSpace
    android_dataspace mDefaultBufferDataSpace;

    // mMaxBufferCount BufferQueue可以分配的GraphicBuffer的最大数量. 可以被consumer设置.
    int mMaxBufferCount;

    // mMaxAcquiredBufferCount Consumer一次可以acquire Buffer的最大数量,默认为1
    int mMaxAcquiredBufferCount;

    // mMaxDequeuedBufferCount Producer一次可以dqueue Buffer的最大数量,默认为1
    int mMaxDequeuedBufferCount;

    // mBufferHasBeenQueued 当有buffer queue到队列中时设置为true, 当释放掉所有buffer的时候设置为false
    bool mBufferHasBeenQueued;

    // mFrameCounter 每当队列中queuebuffer的之后 +1
    uint64_t mFrameCounter;

    // mTransformHint screen rotations标志.
    uint32_t mTransformHint;

    // mSidebandStream is a handle to the sideband buffer stream
    sp<NativeHandle> mSidebandStream;

    // mIsAllocating 表明生产者是否正在请求Gralloc分配GraphicBuffer
    bool mIsAllocating;

    // mAllowAllocation 表明 dequeueBuffer 是否允许请求Gralloc分配新的GraphicBuffer
    bool mAllowAllocation;


    // mAsyncMode 是否启用异步模式:生产者将graphicBuffer入队的时候不会block
    bool mAsyncMode;

    // mSharedBufferMode 是否启用share模式
    bool mSharedBufferMode;

    // ShareBufferMode情况下,即使producer没有通知有新的Buffer可用,consumer也会去获取Buffer
    bool mAutoRefresh;

    // 上一次queue buffer的slot
    int mLastQueuedSlot;

    const uint64_t mUniqueId;

}; // class BufferQueueCore

BufferQueueCore是BufferQueue的核心,定义了Buffer队列一些基本的属性,BufferQueueProducer和BufferQueueConsumer持有同一个BufferQueueCore对象,所以生产者和消费者都可以访问BufferQueue定义的属性。
BufferQueue中定义了一些关键的熟悉

1:BufferQueueDefs::SlotsType mSlots;

mSlots是一个大小为64的BufferSlot数组,表示一个Buffer队列中最多可以有64个Buffer。BufferSlot是一个GraphicBuffer的封装类,定义了和GraphicBuffer相关的一些属性。
如:GraphicBuffer指针,指向一个Gralloc分配的GraphicBuffer。
BufferState, 描述了当前slot位置Buffer的状态。BufferState定义的状态分为以下几种:

    1. FREE:当前这个BufferSlot的所有者为BufferQueue,当前状态可以被Producer调用dequeue方法从队列中取出。当Producer调用dequeue方法获取这个BufferSlot之后,状态会切换成DEQUEUED。
    1. DEQUEUED:当前BufferSlot被Producer从队列中dequeue出来,但是此时Producer仍然不能填充或者修改Buffer内容,直到上一个使用Buffer的消费者发出释放Buffer的Fence信号之后才可以。此时Buffer归生产者所有。当生产者填充完成调用queue方法将其放入队列之后会切换为QUEUED状态,或者调用取消重新切换为FREE状态。
    1. QUEUED:此时Buffer被生产者调用queue方法放入队列,归BufferQueue所属。此时这个slot描述的Buffer可以被Consumer取走。
    1. ACQUIRED:Buffer被Consumer调用acquire方法从队列取走之后,状态变为ACQUIRED状态,此时Consumer并不可访问Buffer的内容,直到收到相关的Fence信号才可以。

2:其他Slot列表

set<int> mFreeSlots -- 表示mSlots中处于FREE状态的BufferSlot,而且此时BufferSlot还没有分配真正的GraphicBuffer

list<int> mFreeBuffers -- 表示mSlots中处于FREE状态的BufferSlot, 且此BufferSlot已经分配了真正的GraphicBuffer。

set<int> mActiveBuffers -- 表示mSlots所有有GraphicBuffer且不属于FREE状态的slot。

BufferQueueCore中其他的属性也已经在注释中解释过了,不在一一分析。

BufferQueueProducer定义


class BufferQueueProducer : public BnGraphicBufferProducer,
                            private IBinder::DeathRecipient {
...
    virtual status_t dequeueBuffer(int* outSlot, sp<Fence>* outFence, uint32_t width,
                                   uint32_t height, PixelFormat format, uint64_t usage,
                                   uint64_t* outBufferAge,
                                   FrameEventHistoryDelta* outTimestamps) override;
    virtual status_t queueBuffer(int slot,
            const QueueBufferInput& input, QueueBufferOutput* output);
    virtual status_t cancelBuffer(int slot, const sp<Fence>& fence);
    virtual status_t connect(const sp<IProducerListener>& listener,
            int api, bool producerControlledByApp, QueueBufferOutput* output);

    // See IGraphicBufferProducer::disconnect
    virtual status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api);

    sp<BufferQueueCore> mCore;

    // This references mCore->mSlots. Lock mCore->mMutex while accessing.
    BufferQueueDefs::SlotsType& mSlots;
}

BufferQueueProducer定义只取了部分内容,有个BufferQueueCore的指针,指向BufferQueueCore对象。还定义了一个引用类型的SlotsType, 和BufferQueueCore中mSlots指向的是同一个mSlots数组对象。
此外,还定义了Producer常用的几个方法
dequeueBuffer: 从BufferQueue中申请新的Buffer
queueBuffer: 将填充好内容的Buffer放入BufferQueue队列
connect: Producer从BufferQueue申请Buffer或者放入填充好的Buffer,必须先调用connect连接到BufferQueue队列上
disconnect: Producer不在对BufferQueue操作的时候,调用disconnect和BufferQueue队列断开连接。

BufferQueueConsumer定义

class BufferQueueConsumer : public BnGraphicBufferConsumer {
    virtual status_t acquireBuffer(BufferItem* outBuffer,
            nsecs_t expectedPresent, uint64_t maxFrameNumber = 0) override;
    virtual status_t releaseBuffer(int slot, uint64_t frameNumber,
            const sp<Fence>& releaseFence, EGLDisplay display,
            EGLSyncKHR fence);
   virtual status_t connect(const sp<IConsumerListener>& consumerListener,
            bool controlledByApp);
   virtual status_t disconnect();

   sp<BufferQueueCore> mCore;

   // This references mCore->mSlots. Lock mCore->mMutex while accessing.
   BufferQueueDefs::SlotsType& mSlots;
}

BufferQueueConsumer定义也只取了部分内容,和Producer定义基本类似。同样也有一个BufferQueueCore的指针指向BufferQueueCore对象,也定义了一个引用类型的SlotsType,和BufferQueueCore的mSlote指向了同一个mSlots数组对象,大小为64。
acquireBuffer: 从BufferQueue队列中获取填充好内容,等待显示的Buffer,这些Buffer是生产者放入队列中的。
releaseBuffer:当Consumer处理完Buffer后,释放Buffer,这样Producer可以重新从队列中申请填充。
connect: Consumer想要从BufferQueue获取Buffer来处理,必须先调用connect连接到BufferQueue队列上
disconnect: Consumer不在对BufferQueue操作的时候,调用disconnect和BufferQueue队列断开连接。

总结

BufferQueue队列简单的分析基本完成了,从BufferQueue的创建已经BufferQueue,BufferQueueProducer和BufferQueueConsumer的定义可以简单了解BufferQueue队列的内容。


BufferQueue

BufferQueueCore定义了Buffer队列的核心内容,保存有一个默认大小为64的BufferSlot数组,表示队列中最多可以有64个图像Buffer,但是我们可以自己定义大小,Layer初始化的时候目前设置为Buffer的数量为3,以前版本是2,这就是Android所说的UI双缓存或者三缓存,也就是时候一个窗口Surface到Layer之间有几个Buffer在其间进行传递,双缓存就是一个在Surface端绘制一个在Layer端显示。BufferQueueProducer和BufferQueueConsumer同时持有BufferQueueCore的对象。

BufferQueueProducer继承自IBufferQueueProducer的Bn端,可以在进程间调用。dequeuebuffer,从队列中申请Buffer, 当填充完内容后,调用queuebuffer将Buffer入队。

BufferQueueConsumer继承自IBufferQueueConsumer的Bn端,可以在进程间调用,acquirebuffer从队列中取得填充好的buffer,处理完成后调用releasebuffer释放buffer为FREE状态后重新回到队列。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 今天看到丫姐的凉拌木耳,慧妈的疙瘩汤超想吃呀,还有楠哥帮我接待姐姐,怀念我们在一起的大家庭……
    箐er_阅读 200评论 0 1
  • 似乎骨子里就透着紧迫感一般,每每看到别人在努力的生活,我们想到的是“啊他好努力,我太堕落了”,我们在羡慕别人的努力...
    是大白呀呀阅读 164评论 0 3
  • 一个好教师意味着什么?首先意味着他是个热爱孩子的人,感到跟孩子交往是一种乐趣,相信每个孩子都能成为好人,善于跟他们...
    安之若素_9aec阅读 89评论 0 0
  • 工作到了最忙碌的时候。 白天几乎一刻都能不能停歇,插着空儿写报道类的文章,体力和脑力受到双重透支。 有的时候,甚至...
    江湖皆是好去处阅读 171评论 0 0
  • 上一章:老婆卸货了 即便是投了99次硬币都是正面,都不代表第100次还是正面,即使准备再充分也有翻车的风险概率...
    不称职的张爸爸阅读 183评论 0 1