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