Android 12(S) 圖形顯示系統 - BufferQueue/BLASTBufferQueue之初識(六)

二的次方發表於2022-03-15

題外話

你有沒有聽見,心裡有一聲咆哮,那一聲咆哮,它好像在說:我就是要從後面追上去!

寫文章真的好痛苦,特別是自己對這方面的知識也一知半解就更加痛苦了。這已經是這個系列的第六篇了,很多次都想放棄了,但最終還是堅持下來了,因為我真的好像搞懂這一塊。


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) 圖形顯示系統 - 開篇

 


我盯著你!

 

相關文章