BufferQueue分析:Buffer隊(duì)列

Buffer隊(duì)列的創(chuàng)建

從Suface創(chuàng)建流程中分析可以鬓催,創(chuàng)建每一個(gè)Layer的時(shí)候,在Layer初始化的時(shí)候會為當(dāng)前Layer創(chuàng)建一個(gè)BufferQueue隊(duì)列淮菠,用于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創(chuàng)建流程中已經(jīng)分析過了
1:BufferQueue創(chuàng)建了一個(gè)的生產(chǎn)者和一個(gè)消費(fèi)者
2:生產(chǎn)者被封裝到了MonitoredProducer中妖谴,傳遞了App端,由Surface持有其代理
3:消費(fèi)這被封裝到了SurfaceFlingerComsumer中酵熙,設(shè)置Layer為內(nèi)容變換監(jiān)聽者轧简,當(dāng)有新的Buffer到來,Layer進(jìn)行處理匾二。

先看下如何創(chuàng)建Buffer隊(duì)列

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

初始化一個(gè)producer指針和一個(gè)consumer指針作為出參給創(chuàng)建BufferQueue的函數(shù)哮独。創(chuàng)建好BufferQueue之后,會將BufferQueue的生產(chǎn)者和消費(fèi)者分別保存在這兩個(gè)變量中假勿。

void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
        sp<IGraphicBufferConsumer>* outConsumer,
        const sp<IGraphicBufferAlloc>& allocator) {
    //創(chuàng)建一個(gè)BufferQueueCore對象
    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
    //創(chuàng)建一個(gè)BufferQueueProducer
    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
    //創(chuàng)建一個(gè)BufferQueueConsumer
    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));

    //將創(chuàng)建的producer和consumer分別保存在出參中
    *outProducer = producer;
    *outConsumer = consumer;
}

createBufferQueue是BufferQueue的靜態(tài)函數(shù)借嗽,該函數(shù)中首先創(chuàng)建了一個(gè)BufferQueueCore對象,然后再以該對象作為參數(shù)創(chuàng)建了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是否還能處理生產(chǎn)者傳遞的圖像
    bool mIsAbandoned;

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

    // mConsumerListener 用于通知已經(jīng)連接的Consumer有新Buffer到來
    sp<IConsumerListener> mConsumerListener;

    // mConnectedApi 表示生產(chǎn)者是否已經(jīng)連接到BufferQueue
    int mConnectedApi;

    // mConnectedProducerToken 用于通知生產(chǎn)者BufferQueue是否已經(jīng)死亡
    sp<IProducerListener> mConnectedProducerListener;

    // mSlots 是一個(gè)大小為64的bufferSlot數(shù)組,每個(gè)BufferSlot描述了一個(gè)GraphicBuffer與其相關(guān)的屬性
    BufferQueueDefs::SlotsType mSlots;

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

    // mFreeSlots 表示所有的FREE狀態(tài)的BufferSlot, 這個(gè)BufferSlot還沒有分配GraphicBuffer緩沖區(qū)
    std::set<int> mFreeSlots;

    // mFreeBuffers 表示所有的FREE狀態(tài)的BufferSlot, 這個(gè)BufferSlot已經(jīng)分配了GraphicBuffer緩沖區(qū)
    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 所有包含有使用狀態(tài)GraphicBuffer的slot.
    std::set<int> mActiveBuffers;

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


    // mDefaultBufferFormat BufferQueue分配的GraphicBuffer的默認(rèn)format
    PixelFormat mDefaultBufferFormat;

    // mDefaultWidth BufferQueue分配的GraphicBuffer的默認(rèn)width
    uint32_t mDefaultWidth;

    // mDefaultHeight BufferQueue分配的GraphicBuffer的默認(rèn)height
    uint32_t mDefaultHeight;

    // mDefaultBufferDataSpace BufferQueue分配的GraphicBuffer的默認(rèn)DataSpace
    android_dataspace mDefaultBufferDataSpace;

    // mMaxBufferCount BufferQueue可以分配的GraphicBuffer的最大數(shù)量. 可以被consumer設(shè)置.
    int mMaxBufferCount;

    // mMaxAcquiredBufferCount Consumer一次可以acquire Buffer的最大數(shù)量恶导,默認(rèn)為1
    int mMaxAcquiredBufferCount;

    // mMaxDequeuedBufferCount Producer一次可以dqueue Buffer的最大數(shù)量,默認(rèn)為1
    int mMaxDequeuedBufferCount;

    // mBufferHasBeenQueued 當(dāng)有buffer queue到隊(duì)列中時(shí)設(shè)置為true, 當(dāng)釋放掉所有buffer的時(shí)候設(shè)置為false
    bool mBufferHasBeenQueued;

    // mFrameCounter 每當(dāng)隊(duì)列中queuebuffer的之后 +1
    uint64_t mFrameCounter;

    // mTransformHint screen rotations標(biāo)志.
    uint32_t mTransformHint;

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

    // mIsAllocating 表明生產(chǎn)者是否正在請求Gralloc分配GraphicBuffer
    bool mIsAllocating;

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


    // mAsyncMode 是否啟用異步模式:生產(chǎn)者將graphicBuffer入隊(duì)的時(shí)候不會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隊(duì)列一些基本的屬性删窒,BufferQueueProducer和BufferQueueConsumer持有同一個(gè)BufferQueueCore對象裂垦,所以生產(chǎn)者和消費(fèi)者都可以訪問BufferQueue定義的屬性。
BufferQueue中定義了一些關(guān)鍵的熟悉

1:BufferQueueDefs::SlotsType mSlots;

mSlots是一個(gè)大小為64的BufferSlot數(shù)組肌索,表示一個(gè)Buffer隊(duì)列中最多可以有64個(gè)Buffer蕉拢。BufferSlot是一個(gè)GraphicBuffer的封裝類,定義了和GraphicBuffer相關(guān)的一些屬性诚亚。
如:GraphicBuffer指針晕换,指向一個(gè)Gralloc分配的GraphicBuffer。
BufferState, 描述了當(dāng)前slot位置Buffer的狀態(tài)站宗。BufferState定義的狀態(tài)分為以下幾種:

    1. FREE:當(dāng)前這個(gè)BufferSlot的所有者為BufferQueue闸准,當(dāng)前狀態(tài)可以被Producer調(diào)用dequeue方法從隊(duì)列中取出。當(dāng)Producer調(diào)用dequeue方法獲取這個(gè)BufferSlot之后梢灭,狀態(tài)會切換成DEQUEUED夷家。
    1. DEQUEUED:當(dāng)前BufferSlot被Producer從隊(duì)列中dequeue出來蒸其,但是此時(shí)Producer仍然不能填充或者修改Buffer內(nèi)容,直到上一個(gè)使用Buffer的消費(fèi)者發(fā)出釋放Buffer的Fence信號之后才可以库快。此時(shí)Buffer歸生產(chǎn)者所有摸袁。當(dāng)生產(chǎn)者填充完成調(diào)用queue方法將其放入隊(duì)列之后會切換為QUEUED狀態(tài),或者調(diào)用取消重新切換為FREE狀態(tài)缺谴。
    1. QUEUED:此時(shí)Buffer被生產(chǎn)者調(diào)用queue方法放入隊(duì)列但惶,歸BufferQueue所屬耳鸯。此時(shí)這個(gè)slot描述的Buffer可以被Consumer取走湿蛔。
    1. ACQUIRED:Buffer被Consumer調(diào)用acquire方法從隊(duì)列取走之后,狀態(tài)變?yōu)锳CQUIRED狀態(tài)县爬,此時(shí)Consumer并不可訪問Buffer的內(nèi)容阳啥,直到收到相關(guān)的Fence信號才可以。

2:其他Slot列表

set<int> mFreeSlots -- 表示mSlots中處于FREE狀態(tài)的BufferSlot财喳,而且此時(shí)BufferSlot還沒有分配真正的GraphicBuffer

list<int> mFreeBuffers -- 表示mSlots中處于FREE狀態(tài)的BufferSlot, 且此BufferSlot已經(jīng)分配了真正的GraphicBuffer察迟。

set<int> mActiveBuffers -- 表示mSlots所有有GraphicBuffer且不屬于FREE狀態(tài)的slot。

BufferQueueCore中其他的屬性也已經(jīng)在注釋中解釋過了耳高,不在一一分析扎瓶。

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定義只取了部分內(nèi)容,有個(gè)BufferQueueCore的指針泌枪,指向BufferQueueCore對象概荷。還定義了一個(gè)引用類型的SlotsType, 和BufferQueueCore中mSlots指向的是同一個(gè)mSlots數(shù)組對象碌燕。
此外误证,還定義了Producer常用的幾個(gè)方法
dequeueBuffer: 從BufferQueue中申請新的Buffer
queueBuffer: 將填充好內(nèi)容的Buffer放入BufferQueue隊(duì)列
connect: Producer從BufferQueue申請Buffer或者放入填充好的Buffer,必須先調(diào)用connect連接到BufferQueue隊(duì)列上
disconnect: Producer不在對BufferQueue操作的時(shí)候修壕,調(diào)用disconnect和BufferQueue隊(duì)列斷開連接愈捅。

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定義也只取了部分內(nèi)容,和Producer定義基本類似慈鸠。同樣也有一個(gè)BufferQueueCore的指針指向BufferQueueCore對象蓝谨,也定義了一個(gè)引用類型的SlotsType,和BufferQueueCore的mSlote指向了同一個(gè)mSlots數(shù)組對象青团,大小為64譬巫。
acquireBuffer: 從BufferQueue隊(duì)列中獲取填充好內(nèi)容,等待顯示的Buffer壶冒,這些Buffer是生產(chǎn)者放入隊(duì)列中的缕题。
releaseBuffer:當(dāng)Consumer處理完Buffer后,釋放Buffer胖腾,這樣Producer可以重新從隊(duì)列中申請?zhí)畛洹?br> connect: Consumer想要從BufferQueue獲取Buffer來處理烟零,必須先調(diào)用connect連接到BufferQueue隊(duì)列上
disconnect: Consumer不在對BufferQueue操作的時(shí)候瘪松,調(diào)用disconnect和BufferQueue隊(duì)列斷開連接。

總結(jié)

BufferQueue隊(duì)列簡單的分析基本完成了锨阿,從BufferQueue的創(chuàng)建已經(jīng)BufferQueue宵睦,BufferQueueProducer和BufferQueueConsumer的定義可以簡單了解BufferQueue隊(duì)列的內(nèi)容。


BufferQueue

BufferQueueCore定義了Buffer隊(duì)列的核心內(nèi)容墅诡,保存有一個(gè)默認(rèn)大小為64的BufferSlot數(shù)組壳嚎,表示隊(duì)列中最多可以有64個(gè)圖像Buffer,但是我們可以自己定義大小末早,Layer初始化的時(shí)候目前設(shè)置為Buffer的數(shù)量為3烟馅,以前版本是2,這就是Android所說的UI雙緩存或者三緩存然磷,也就是時(shí)候一個(gè)窗口Surface到Layer之間有幾個(gè)Buffer在其間進(jìn)行傳遞郑趁,雙緩存就是一個(gè)在Surface端繪制一個(gè)在Layer端顯示。BufferQueueProducer和BufferQueueConsumer同時(shí)持有BufferQueueCore的對象姿搜。

BufferQueueProducer繼承自IBufferQueueProducer的Bn端寡润,可以在進(jìn)程間調(diào)用。dequeuebuffer舅柜,從隊(duì)列中申請Buffer, 當(dāng)填充完內(nèi)容后梭纹,調(diào)用queuebuffer將Buffer入隊(duì)。

BufferQueueConsumer繼承自IBufferQueueConsumer的Bn端致份,可以在進(jìn)程間調(diào)用变抽,acquirebuffer從隊(duì)列中取得填充好的buffer,處理完成后調(diào)用releasebuffer釋放buffer為FREE狀態(tài)后重新回到隊(duì)列知举。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞬沦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子雇锡,更是在濱河造成了極大的恐慌逛钻,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锰提,死亡現(xiàn)場離奇詭異曙痘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)立肘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門边坤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谅年,你說我怎么就攤上這事茧痒。” “怎么了融蹂?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵旺订,是天一觀的道長弄企。 經(jīng)常有香客問我,道長区拳,這世上最難降的妖魔是什么拘领? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮樱调,結(jié)果婚禮上约素,老公的妹妹穿的比我還像新娘。我一直安慰自己笆凌,他們只是感情好圣猎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著菩颖,像睡著了一般样漆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晦闰,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天,我揣著相機(jī)與錄音鳍怨,去河邊找鬼呻右。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鞋喇,可吹牛的內(nèi)容都是我干的声滥。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼侦香,長吁一口氣:“原來是場噩夢啊……” “哼落塑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起罐韩,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤憾赁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后散吵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體龙考,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年矾睦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晦款。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡枚冗,死狀恐怖缓溅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情赁温,我是刑警寧澤坛怪,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布州藕,位于F島的核電站,受9級特大地震影響酝陈,放射性物質(zhì)發(fā)生泄漏床玻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一沉帮、第九天 我趴在偏房一處隱蔽的房頂上張望锈死。 院中可真熱鬧,春花似錦穆壕、人聲如沸待牵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缨该。三九已至,卻和暖如春川背,著一層夾襖步出監(jiān)牢的瞬間贰拿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工熄云, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留膨更,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓缴允,卻偏偏與公主長得像荚守,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子练般,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 今天看到丫姐的涼拌木耳矗漾,慧媽的疙瘩湯超想吃呀,還有楠哥幫我接待姐姐薄料,懷念我們在一起的大家庭……
    箐er_閱讀 202評論 0 1
  • 似乎骨子里就透著緊迫感一般都办,每每看到別人在努力的生活嫡锌,我們想到的是“啊他好努力,我太墮落了”琳钉,我們在羨慕別人的努力...
    是大白呀呀閱讀 168評論 0 3
  • 一個(gè)好教師意味著什么势木?首先意味著他是個(gè)熱愛孩子的人,感到跟孩子交往是一種樂趣歌懒,相信每個(gè)孩子都能成為好人啦桌,善于跟他們...
    安之若素_9aec閱讀 89評論 0 0
  • 工作到了最忙碌的時(shí)候。 白天幾乎一刻都能不能停歇,插著空兒寫報(bào)道類的文章甫男,體力和腦力受到雙重透支且改。 有的時(shí)候,甚至...
    江湖皆是好去處閱讀 171評論 0 0
  • 上一章:老婆卸貨了 即便是投了99次硬幣都是正面板驳,都不代表第100次還是正面又跛,即使準(zhǔn)備再充分也有翻車的風(fēng)險(xiǎn)概率...
    不稱職的張爸爸閱讀 183評論 0 1