• Android 12(S) 图像显示系统 - BufferQueue/BLASTBufferQueue之初识(六)


    题外话

    你有没有听见,心里有一声咆哮,那一声咆哮,它好像在说:我就是要从后面追上去!

    写文章真的好痛苦,特别是自己对这方面的知识也一知半解就更加痛苦了。这已经是这个系列的第六篇了,很多次都想放弃了,但最终还是坚持下来了,因为我真的好像搞懂这一块。


    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
        // 由于适配器在客户端进程中,显式设置 dequeue 超时,以便 dequeueBuffer 流程阻塞
        mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());
    
        // safe default, most producers are expected to override this
        // 默认设置最大dequeue buffer 数量
        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);
        // 设置缓冲区Size
        mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
        mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
        mBufferItemConsumer->setBlastBufferQueue(this);
        // 通过SF端计算并获取最大可消费缓冲区数量
        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");
        // 创建BufferQueue核心类,主要负责缓冲区的调度工作
        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 {
      ......
    }

     


    隐蔽地点埋点bug -- 二的次方


    进一步再看看 BBQSurface的构造函数

    BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
                   const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
              : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}

    再对照一下Surface的构造函数

    Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
                     const sp<IBinder>& surfaceControlHandle)
          : mGraphicBufferProducer(bufferProducer),
           ...... ) {
    
        ......
    
        mProducerControlledByApp = controlledByApp;
    
        mSurfaceControlHandle = surfaceControlHandle;
    }

    Surface中有:

    图形缓冲生产者:mGraphicBufferProducer,这个就是BLASTBufferQueue::createBufferQueue时创建的,并一路传递过来;

    SurfaceControl句柄: mSurfaceCtrolHandle是 SurfaceControl::generateSurfaceLocked()中mClient->createSurface时获取的,并一路传递下来;

     

    需要理理/想想

    我们初步可以看到一些概念:
        一个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建立联系。

     

    关于BLASTBufferQueue的理解,推荐一篇文章:

    https://www.jianshu.com/p/cdc60627df90

     


    另外补充一点

    在Java层,也就是SurfaceView中,有持有两个非常重要的成员:

    private SurfaceControl mBlastSurfaceControl;
    private BLASTBufferQueue mBlastBufferQueue;

    具体的可以看代码

    /frameworks/base/core/java/android/view/SurfaceView.java

    Native层的SurfaceControl & BLASTBufferQueue都通过JNI串接到了Java层,并提供了API

    Java API:

    /frameworks/base/core/java/android/view/SurfaceControl.java

    /frameworks/base/graphics/java/android/graphics/BLASTBufferQueue.java

    JNI API:

    /frameworks/base/core/jni/android_graphics_BLASTBufferQueue.cpp

    /frameworks/base/core/jni/android_view_SurfaceControl.cpp

    SurfaceView自己持有SurfaceControl & BLASTBufferQueue的对象并进行控制,在SurfaceView引入了 BLASTBufferQueue,这样同时将BufferQueue的相关逻辑转移给了Application,进而简化SurfaceFlinger过于复杂的逻辑。

     

    3 小结

    这一篇文章中,我们顺着示例应用的逻辑,引入了BufferQueue的概念,介绍了什么时候,如何创建了BufferQueue。

     

     


    必读:

    Android 12(S) 图像显示系统 - 开篇

     


    我盯着你!

     

  • 相关阅读:
    前后端分离springBoot项目集成部署vue
    L40.linux命令每日一练 -- 第七章 Linux用户管理及用户信息查询命令 -- useradd和usermod
    双软企业认证与税收优惠政策讲解(比较齐全)
    [附源码]Python计算机毕业设计Django仓库管理系统
    【面试】找到一个数组中超过一半的数——摩尔投票算法
    3D Web轻量化引擎HOOPS Communicator如何优化AEC领域3D大模型体验?
    MySQL事务并发问题和MVCC机制
    灵活的IP网络测试工具——— X-Launch
    虚拟标签做添加点击事件,e.target 方法
    Python 教程之运算符(1)—— python 中的基本运算符(上)
  • 原文地址:https://www.cnblogs.com/roger-yu/p/15773008.html