簡單梳理Android BufferQueue原理(基於P)

一. 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章