題外話
你有沒有聽見,心裡有一聲咆哮,那一聲咆哮,它好像在說:我就是要從後面追上去!
寫文章真的好痛苦,特別是自己對這方面的知識也一知半解就更加痛苦了。這已經是這個系列的第六篇了,很多次都想放棄了,但最終還是堅持下來了,因為我真的好像搞懂這一塊。
1 前言
前面一篇文章中,我們已經介紹了createSurface的流程,也在SurfaceFlinger中去建立了圖層layer,但一直沒有看到buffer queue的蹤影。其實,據我觀察 Android 12 將BufferQueue的相關邏輯移出了SurfaceFlinger。這一篇文章中我們就會跟隨之前寫的應用的程式碼邏輯,看看BufferQueue的相關邏輯是如何引入的?又是如何工作的?
2 建立BufferQueue/BLASTBufferQueue
接著從我們的示例應用講起,程式碼在文章:Android 12(S) 圖形顯示系統 - 示例應用(二)
建立native surface後接下下就是要準備去繪圖了,流程就走到了 drawNativeSurface()這個方法中,先看內容:
int drawNativeSurface(sp<NativeSurfaceWrapper> nativeSurface) {
status_t err = NO_ERROR;
int countFrame = 0;
ANativeWindowBuffer *nativeBuffer = nullptr;
ANativeWindow* nativeWindow = nativeSurface->getSurface().get();
...
}
drawNativeSurface這個方法中首先去呼叫了我們定義的NativeSurfaceWrapper::getSurface方法:
sp<ANativeWindow> NativeSurfaceWrapper::getSurface() const {
sp<ANativeWindow> anw = mSurfaceControl->getSurface();
return anw;
}
getSurface方法中,mSurfaceControl就是上一篇中Android 12(S) 圖形顯示系統 - createSurface的流程(五)建立得到的,它封裝了SurfaceFlinger建立的BufferStateLayer的資訊。接著來到了SurfaceControl::getSurface()
* /frameworks/native/libs/gui/SurfaceControl.cpp
sp<Surface> SurfaceControl::getSurface()
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == nullptr) {
return generateSurfaceLocked();
}
return mSurfaceData;
}
其中 mSurfaceData定義如下:
* /frameworks/native/libs/gui/include/gui/SurfaceControl.h
mutable sp<Surface> mSurfaceData;
因為 SurfaceControl::getSurface() 第一次被呼叫,此時 mSurfaceData為null,進而會執行 SurfaceControl::generateSurfaceLocked()
sp<Surface> SurfaceControl::generateSurfaceLocked()
{
uint32_t ignore;
auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow |
ISurfaceComposerClient::eOpaque);
mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
flags, mHandle, {}, &ignore);
mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);
// This surface is always consumed by SurfaceFlinger, so the
// producerControlledByApp value doesn't matter; using false.
mSurfaceData = mBbq->getSurface(true);
return mSurfaceData;
}
看到了沒,我們念念不忘,朝思暮想 ,魂牽夢繞的BufferQueue的邏輯 ==> BLASTBufferQueue <== 終於千呼萬喚始出來!!!
class SurfaceControl : public RefBase
...
private:
sp<SurfaceComposerClient> mClient; // 應用建立的SurfaceComposerClient物件指標,裡面封裝了和SurfaceFlinger通訊的Binder客戶端
sp<IBinder> mHandle; // 應用中顯式建立的layer handle,這是個BufferStateLayer 它作為parent
sp<IGraphicBufferProducer> mGraphicBufferProducer; // 這個貌似沒有實際用了?
mutable Mutex mLock;
mutable sp<Surface> mSurfaceData; //
mutable sp<BLASTBufferQueue> mBbq; // BLASTBufferQueue物件例項
mutable sp<SurfaceControl> mBbqChild; // child layer,它會和mBbq相關聯
int32_t mLayerId; // layer id
uint32_t mTransformHint; // 方向
uint32_t mWidth; // surface 寬
uint32_t mHeight; // surface 高
PixelFormat mFormat;
uint32_t mCreateFlags; // createSurface的標誌資訊
};
SurfaceControl中一些成員和類圖,下圖可能並不完全準確
我們看看generateSurfaceLocked都幹了什麼:
♦ mCreateFlags是一個uint32_t型別的變數,表示createSurface的一些屬性標識,這個值其實就是我們呼叫surfaceComposerClient->createSurface時new SurfaceControl傳遞下來的
♦ mClient,型別是sp<SurfaceComposerClient> 這個值也是我們呼叫surfaceComposerClient->createSurface時new SurfaceControl傳遞下來的
♦ mClient->createSurface 流程和我們上一章的流程是一樣的,傳遞的引數有點差異
>> surface/layer的名字為“bbq-wrapper”
>> 待建立的surface/layer設定其parent是mHandle所指向的layer,,mHandle也即是我們應用中顯示建立的那個名字為"NativeSFDemo"的layer
♦ 新建立的這個 child surface 或叫做 child layer的資訊同樣被封裝到一個SurfceControl物件中,儲存在 mBbqChild
我們在Android 12(S) 圖形顯示系統 - 示例應用(二)文章最後曾留下一個問題,看到這裡你是不是就明白了?
主角登場
mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);
♦ 建立一個BLASTBufferQueue物件,儲存在mBbq中
♦ 最後呼叫BLASTBufferQueue::getSurface函式,返回一個sp<Surface>給應用,之後應用就可以通過這個Surface操做BufferQueue了。
BLASTBufferQueue的構建
先看其建構函式的程式碼:
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
int width, int height, int32_t format)
: mSurfaceControl(surface),
mSize(width, height),
mRequestedSize(mSize),
mFormat(format),
mNextTransaction(nullptr) {
createBufferQueue(&mProducer, &mConsumer);
// since the adapter is in the client process, set dequeue timeout
// explicitly so that dequeueBuffer will block
mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());
// safe default, most producers are expected to override this
mProducer->setMaxDequeuedBufferCount(2);
mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
GraphicBuffer::USAGE_HW_COMPOSER |
GraphicBuffer::USAGE_HW_TEXTURE,
1, false);
static int32_t id = 0;
mName = name + "#" + std::to_string(id);
auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id);
mQueuedBufferTrace = "QueuedBuffer - " + mName + "BLAST#" + std::to_string(id);
id++;
mBufferItemConsumer->setName(String8(consumerName.c_str()));
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
mBufferItemConsumer->setBlastBufferQueue(this);
ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
SurfaceComposerClient::Transaction()
.setFlags(surface, layer_state_t::eEnableBackpressure,
layer_state_t::eEnableBackpressure)
.setApplyToken(mApplyToken)
.apply();
mNumAcquired = 0;
mNumFrameAvailable = 0;
BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width,
height, format, mTransformHint);
}
可以看到建構函式中主要是去建立BufferQueue並初始化生成者mProducer和消費者mConsumer這兩個變數,然後進行了一些引數和Listener的設定
createBufferQueue
* /frameworks/native/libs/gui/BLASTBufferQueue.cpp
// Similar to BufferQueue::createBufferQueue but creates an adapter specific bufferqueue producer.
// This BQP allows invoking client specified ProducerListeners and invoke them asynchronously,
// emulating one way binder call behavior. Without this, if the listener calls back into the queue,
// we can deadlock.
void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer) {
LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BLASTBufferQueue: outProducer must not be NULL");
LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BLASTBufferQueue: outConsumer must not be NULL");
sp<BufferQueueCore> core(new BufferQueueCore());
LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore");
sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core));
LOG_ALWAYS_FATAL_IF(producer == nullptr,
"BLASTBufferQueue: failed to create BBQBufferQueueProducer");
sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
consumer->setAllowExtraAcquire(true);
LOG_ALWAYS_FATAL_IF(consumer == nullptr,
"BLASTBufferQueue: failed to create BufferQueueConsumer");
*outProducer = producer;
*outConsumer = consumer;
}
建立BufferQueueCore
建立BBQBufferQueueProducer
建立BufferQueueConsumer
再來看一張類圖,BufferQueue相關類的關係,先有個初步的印象
BLASTBufferQueue::getSurface
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
std::unique_lock _lock{mMutex};
sp<IBinder> scHandle = nullptr;
if (includeSurfaceControlHandle && mSurfaceControl) {
scHandle = mSurfaceControl->getHandle();
}
return new BBQSurface(mProducer, true, scHandle, this);
}
BLASTBufferQueue::getSurface方法中會去建立一個BBQSurface, 這個類繼承自Surface,其中儲存了對應layer的handle
class BBQSurface : public Surface {
......
}
需要理理/想想
我們初步可以看到一些概念:
一個BLASTBufferQueue(BufferQueue)對應一個Layer,一個BufferQueue中有多個Buffer,一般是2個或者3個。
一個BLASTBufferQueue(BufferQueue)有一個Producer,一個Consumer
結合前面的分析,一個Surface和一個Layer也是一一對應的,和視窗也是一一對應的。
可見,BLASTBufferQueue(BufferQueue)就是兩個連線紐帶,連線著Producer和Consumer。
Android 12之前的版本是在SurfaceFlinger的BufferLayer中去建立BufferQueue,而Android 12把這個邏輯從SurfaceFlinger移出來了,而是在BLASTBufferQueue中去建立BufferQueue。BLASTBufferQueue會關聯到特定的layer,並與SurfaceFlinger互動來和layer建立聯絡。
3 小結
這一篇文章中,我們順著示例應用的邏輯,引入了BufferQueue的概念,介紹了什麼時候,如何建立了BufferQueue。
必讀:
Android 12(S) 圖形顯示系統 - 開篇
我盯著你!