1. 程式人生 > >Android-Fk:BufferQueue學習整理

Android-Fk:BufferQueue學習整理

一. BufferQueue概述

BufferQueue可以理解為一個生產者-消費者”模型,對GraphicBuffer管理的一種機制。
需注意的是,可以將BufferQueue當作是一個演算法結構,並不是只有Surfaceflinger會使用到,其他程序只要有GraphicBuffer的消費地方都會使用到。

二. BufferQueue結構

在這裡插入圖片描述
一般是在消費者程序呼叫BufferQueue的createBufferQueue建立BufferQueueCore,BufferQueueProducer和BufferQueueConsumer物件。
對應著三個重要部分,資料,生產者,消費者,三者關係:
在這裡插入圖片描述

圖形生產者(如相機,View繪製等)先向BufferQueue申請GraphicBuffer,填充完GraphicBuffer後,將GraphicBuffer移交給BufferQueue,BufferQueue會通知圖形消費者(如Surfaceflinger,ImageReader,GLConsumer等)

BufferQueue採用了binder和共享記憶體機制,因此可以高效地在程序間傳遞圖形資料,Producer和Consumer可能不在同一程序,GraphicBurffer可以看作是一塊共享記憶體。

BufferQueueProducer和BufferQueueConsumer分別實現了IGraphicBufferProducer和IGraphicBufferConsumer binder介面,

在消費者程序呼叫consumerConnect向BufferQueueCore註冊IConsumerListener,這樣有新資料的時候就可以通過IConsumerListener的onFrameAvailable()回撥通知對應的消費者,
收到通知後,消費者通過IGraphicBufferConsumer從BufferQueueCore取出GraphicBuffer,使用完之後將GraphicBuffer放回到BufferQueueCore。

在生產者程序獲取到IGraphicBufferProducer介面後,可以通過connect向BufferQueueCore註冊IProducerListener,這樣在消費者將GraphicBuffer放回BufferQueueCore時可以通知生產者,生產者可以通過IGraphicBufferProducer向BufferQueueCore申請GraphicBuffer,填充完GraphicBuffer後,將GraphicBuffer提交給BufferQueueCore,然後由BufferQueueCore來通知消費者。

通過如下介面實現通知:

void BufferQueue::ProxyConsumerListener::onFrameAvailable(
        const BufferItem& item) {
    sp<ConsumerListener> listener(mConsumerListener.promote());
    if (listener != NULL) {
        listener->onFrameAvailable(item);
    }
}
void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
    sp<ConsumerListener> listener(mConsumerListener.promote());
    if (listener != NULL) {
        listener->onBuffersReleased();
    }
}

三.使用到BufferQueue的場景

3.1 Activity View的顯示

應用Activity View介面顯示,介面的Window是GraphicBuffer生產者,不斷dequeue buffer出來往其中寫資料,SurfaceFlinger是GraphicBuffer的消費者,不斷acqure buffer出來合成顯示。
在這裡插入圖片描述
BufferLayer建立時:

frameworks/native/services/surfaceflinger/BufferLayer.cpp
void BufferLayer::onFirstRef() {
    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
    sp<IGraphicBufferProducer> producer;//生產者
    sp<IGraphicBufferConsumer> consumer;//消費者
    BufferQueue::createBufferQueue(&producer, &consumer, true);//建立Queue
    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);
}

3.2 SurfaceTexture

相機中preview使用到的TextureView中的成員SurfaceTexture就是個自帶BufferQueue的組建,在消費者程序,具體之後會詳細講述SurfaceTexture。
在這裡插入圖片描述
SurfaceTexture初始化:

frameworks/base/core/jni/android/graphics/SurfaceTexture.cpp
static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
        jint texName, jboolean singleBufferMode, jobject weakThiz)
{
    sp<IGraphicBufferProducer> producer;//生產者
    sp<IGraphicBufferConsumer> consumer;//消費者
    BufferQueue::createBufferQueue(&producer, &consumer);
    sp<GLConsumer> surfaceTexture;
    ...
        //看出來SurfaceTexture中歐的BufferQueue的消費者是一個GLConsumer
        surfaceTexture = new GLConsumer(consumer, texName,
                GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);
    ...


    SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
    SurfaceTexture_setProducer(env, thiz, producer);

    jclass clazz = env->GetObjectClass(thiz);
    
    sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
            clazz));
     //設定監聽
    surfaceTexture->setFrameAvailableListener(ctx);
    SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
}

3.3 ImageReader

相機中儲存圖片的使用的ImageReader也是在消費者程序,初始化時及自己建立了BufferQueue,在消費者程序,及相機應用是消費者,具體之後會詳細講述ImageReader。
在這裡插入圖片描述
ImageReader初始化,如上類似:

frameworks/native/libs/gui/BufferQueueConsumer.cpp
static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint width, jint height,
                             jint format, jint maxImages, jlong ndkUsage)
{
    sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages));

    sp<IGraphicBufferProducer> gbProducer;
    sp<IGraphicBufferConsumer> gbConsumer;
    BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
    sp<BufferItemConsumer> bufferConsumer;
  
    bufferConsumer = new BufferItemConsumer(gbConsumer, consumerUsage, maxImages,
            /*controlledByApp*/true);

    ctx->setBufferConsumer(bufferConsumer);
    bufferConsumer->setName(consumerName);

    ctx->setProducer(gbProducer);
    bufferConsumer->setFrameAvailableListener(ctx);
  
}

四. 總結

使用BufferQueue的地方還有很多,可以在AOSP程式碼裡搜"BufferQueue::createBufferQueue",一般建立BufferQueue的是在消費者程序,GraphicBuffer是在消費者程序裡分配,而一系列的呼叫邏輯,無非就是將BufferQueue在初始化時建立的Producer指標和Consumer指標關聯到對應程序中的生產者和消費者上,這一點下面會詳述,本篇主要為後面學習Surface鋪墊。

參考部落格:
https://www.jianshu.com/p/edd7d264be73
https://blog.csdn.net/u014409795/article/details/51276468