• Android 12(S) 图像显示系统 - BufferQueue的工作流程(八)


    题外话


    最近总有一个感觉:在不断学习中,越发的感觉自己的无知,自己是不是要从“愚昧之巅”掉到“绝望之谷”了,哈哈哈🐶

    邓宁-克鲁格效应

     

    一、前言


    前面的文章中已经讲解了如何去创建一个Surface,也讲了一些操作Surface的知识,接下来就是如何利用这个Surface进行绘图呢?

    在此开始讲解buffer queue的工作流程,看看图形数据是怎样流转的? 图形缓冲区的申请和消费流程是怎样的?有哪些核心类?等等问题在接下来的文章中陆续展开。

    这篇文章中,先介绍一些基本概念的东西,帮助后续内容展开打下基础。

    ♦ 生产者与消费者模型

    ♦ 关于图形缓冲区队列的核心类

    ♦ BufferState介绍

    ♦ BufferSlot介绍

    ♦ 一些buffer数组的介绍

    二、生产者与消费者模型


    在Android 12系统中,BLASTBufferQueue中完成buffer queue相关组件的初始化。整个生产消费模型都在客户端,图形缓冲区的出队、入队、获取等操作都在客户端完成,预示着生产者模型从远程通讯变成了本地通讯。带来的改变就是客户端需要通过事务Transaction来向SF端提交Buffer与图层的属性。
     
    对于Android 12 后的系统,我自己理解下图来表示生产者-消费者模型中各个组件间的协同工作:
     

    或者如下这张图,关于如何清楚表示BLASTBufferQueue的地位???

     

    注:上图可能表达的意思也不准确,但应留意Android 12之后与旧版本的区别

     

    三、关于图形缓冲区队列的核心类


    先给出一个涉及到的相关类的关系图,这幅图并不完整,很多细节也没有呈现出来,只是大概描述各元素间的关系,便于我们看到全貌。

    其中几个比较重要的类,也是后面出场次数比较多的有:

    ♦ BLASTBufferQueue

    ♦ BufferQueueCore

    ♦ BufferQueueProducer

    ♦ BufferQueueConsumer

    ♦ Surface

    ♦ SurfaceControl

     

    四、BufferSlot介绍


    源码

    /frameworks/native/libs/gui/include/gui/BufferSlot.h

    定义

    BufferSlot理解为缓冲槽,一个存放buffer及其信息的地方。这个结构体中主要有如下内容:

    我们主要看一下几个成员变量:

    ♦ mGraphicBuffer代表一块图形缓冲区GraphicBuffer,用于存储绘制图形的数据;

    ♦ mBufferState类型为BufferState,标记当前buffer slot所处的状态;

    ♦ mNeedsReallocation,是否需要重新分配这个buffer;

    ♦ mFence,用于资源同步

     


    关于mFence的解释,源码中有以断详细的注释,我觉得很值得读一读:

        // mFence is a fence which will signal when work initiated by the
        // previous owner of the buffer is finished. When the buffer is FREE,
        // the fence indicates when the consumer has finished reading
        // from the buffer, or when the producer has finished writing if it
        // called cancelBuffer after queueing some writes. When the buffer is
        // QUEUED, it indicates when the producer has finished filling the
        // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
        // passed to the consumer or producer along with ownership of the
        // buffer, and mFence is set to NO_FENCE.
        sp<Fence> mFence;

    用我蹩脚的英文->中文,我大概直译一下:

    1. mFence是一个围栏,当buffer的前所有者的工作(即对这个buffer的处理操作)完成时,它会发出信号;

    2. 当buffer处于FREE状态时,fence指示consumer何时已完成从buffer的读取,或者如果producer在写入一些东西后调用了cancelBuffer,此时fence指示producer何时已完成写入

    3. 当buffer处于QUEUED状态时,它指示producer何时完成buffer的填充(数据写好了,通知consumer使用);

    4. 当buffer处于DEQUEUED/ACQUIRED状态时,fence已连同buffer的所有权一起传递给consumer或producer,并且mFence设置为NO_FENCE;

    构造函数,默认其mGraphicBuffer是nullptr,即没有绑定GraphicBuffer,也就是没有分配实际的图形缓存了。

        BufferSlot()
        : mGraphicBuffer(nullptr),
          mEglDisplay(EGL_NO_DISPLAY),
          mBufferState(),
          mRequestBufferCalled(false),
          mFrameNumber(0),
          mEglFence(EGL_NO_SYNC_KHR),
          mFence(Fence::NO_FENCE),
          mAcquireCalled(false),
          mNeedsReallocation(false) {
        }

     

     

    五、BufferState介绍


    源码

     /frameworks/native/libs/gui/include/gui/BufferSlot.h

    定义

    BufferState用于跟踪记录一个buffer slot(缓冲槽)所处的状态。如下这个类图描述了BufferState中定义的基本内容:

    ♦ 用于描述缓冲区状态的3个uint32_t变量(mDequeueCount/mQueueCount/mAcquireCount)和1个bool变量(mShared);

    ♦ 用于查询缓冲区状态的函数,isXXX();

    ♦ 用于改变/设置缓冲区状态的函数,比如 void dequeue() {...}  and  void queue() {...}

    状态

    BufferState用于跟踪记录一个buffer slot(缓冲槽)所处的状态。一个buffer可以处于以下5种状态之一。

    状态 说明
    FREE

    此状态下buffer可以被producer通过dequeued获取;

    slot被BufferQueue所拥有,producer调用dequeueBuffer获取该buffer后其状态转为DEQUEUED

    DEQUEUED

    此状态表示该buffer已经被producer通过dequeued获取到,但还没有被queue或cancel。

    一旦与该buffer相关联的fence发出信号,producer就可以修改buffer的内容了。

    这种状态下slot属于producer所有,当调用queueBuffer or attachBuffer后可转为QUEUED状态,或调用cancelBuffer or detachBuffer转为FREE状态

    QUEUED

    此状态表示该buffer已经被producer填充数据,入队列让consumer使用。

    buffer内容可能会在有限的时间内继续修改,因此在相关fence发出信号之前,不得访问内容。

    此时slot归BufferQueue所有,buffer状态可以转为ACQUIRED(via acquireBuffer) 或FREE(另一个buffer异步模式下入队列)

    ACQUIRED

    此状态表示该buffer被consumer取得。fence信号发出后,消费者就可以访问其内容了。

    slot被consumer所拥有。 当调用releaseBuffer (or detachBuffer)可以转为FREE

    SHARED 表示此缓冲区正在共享缓冲区模式下使用(还没太理解这个)

     

    在显示系统中,实现流畅的绘制和显示,一般的buffer大致会经过如下这个流程:

    FREE -> DEQUEUED -> QUEUED -> ACQUIRED -> FREE

     

    如下图描述的状态转换的基本逻辑:

    如何辨别当前状态?

    状态是根据3个uint32_t变量(mDequeueCount/mQueueCount/mAcquireCount)和1个bool变量(mShared)的值来进行判断的,如下表格就是各种状态下各个变量的组合情况:

     

    六、几个队列/数组大概解释


    在图形缓冲区队列的逻辑中,有几处队列、数组,我们大概看一看他们代表了什么意思。

    BufferQueue最多可以跟踪的buffer的数量

    /frameworks/native/libs/ui/include/ui/BufferQueueDefs.h

    // BufferQueue will keep track of at most this value of buffers.
    // Attempts at runtime to increase the number of buffers past this
    // will fail.
    static constexpr int NUM_BUFFER_SLOTS = 64;

     

    SlotsType的定义--存储64个BufferSlot的数组

    /frameworks/native/libs/gui/include/gui/BufferQueueDefs.h

    namespace BufferQueueDefs {
        typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
    } // namespace BufferQueueDefs

     

    BufferQueueCore中的buffer slot数组

    /frameworks/native/libs/gui/include/gui/BufferQueueCore.h

    // mSlots is an array of buffer slots that must be mirrored on the producer
        // side. This allows buffer ownership to be transferred between the producer
        // and consumer without sending a GraphicBuffer over Binder. The entire
        // array is initialized to NULL at construction time, and buffers are
        // allocated for a slot when requestBuffer is called with that slot's index.
        BufferQueueDefs::SlotsType mSlots;
    
        // mQueue is a FIFO of queued buffers used in synchronous mode.
        // 定义 typedef Vector<BufferItem> Fifo;
        Fifo mQueue;
    
        // mFreeSlots contains all of the slots which are FREE and do not currently
        // have a buffer attached.
        std::set<int> mFreeSlots;
    
        // mFreeBuffers contains all of the slots which are FREE and currently have
        // a buffer attached.
        std::list<int> mFreeBuffers;
    
        // mUnusedSlots contains all slots that are currently unused. They should be
        // free and not have a buffer attached.
        std::list<int> mUnusedSlots;
    
        // mActiveBuffers contains all slots which have a non-FREE buffer attached.
        std::set<int> mActiveBuffers;

     

    ♦  mSlots :BufferSlot数组,默认大小是64个,这个数组会被映射到BufferQueueProducer/BufferQueueConsuer类中;

    ♦  mQueue :BufferItem类型的数组,Producer调用queueBuffer后,其实就是queue到这个数组里面;

    ♦  mFreeSlots :没有绑定GraphicBuffer且状态为FREE的BufferSlot集合;

    ♦  mFreeBuffers :绑定了GraphicBuffer且状态为FREE的BufferSlot集合;

    ♦  mUnusedSlots:代表当前没有使用的 BufferSlot 集合,这个和mFreeSlots有什么差异,还没搞懂。。。

    ♦  mActiveBuffers :绑定了GraphicBuffer且状态为非FREE的BufferSlot集合;

     


    Tips:

    mFreeSlots/mFreeBuffers/mUnusedSlots/mActiveBuffers存储的都是int类型的index,根据这个index去mSlots中获取对应的BufferSlot及GraphicBuffer.

    我的理解之所以划分出这么多不同的数组,都是为了给 BufferSlot 分类,以便获取 GraphicBuffer 时更加高效。


     

    BufferQueueProducer中的buffer slot 数组

    看器构造函数:

    BufferQueueProducer.cpp 文件定义
    BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
            bool consumerIsSurfaceFlinger) :
        mCore(core),
        mSlots(core->mSlots),
    
    
    BufferQueueProducer.h 头文件定义
    // This references mCore->mSlots. Lock mCore->mMutex while accessing.
    BufferQueueDefs::SlotsType& mSlots;

    BLASTBufferQueue::createBufferQueue中,实例化一个BufferQueueProducer对象,其构造函数在初始化成员变量时,在会直接将前面创建好的 BufferQueueCore 和 mSlots 赋值到  的成员变量mSlots中。

    BufferQueueProducer::mSlots 是 BufferQueueCore::mSlots的映射/引用,其实就是一个东东!

     

    BufferQueueConsumer中的buffer slot数组

    BufferQueueConsumer.cpp中的定义:
    BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
        mCore(core),
        mSlots(core->mSlots),
        mConsumerName() {}
    
    BufferQueueConsumer.h中的定义:
    // This references mCore->mSlots. Lock mCore->mMutex while accessing.
    BufferQueueDefs::SlotsType& mSlots;

    BLASTBufferQueue::createBufferQueue中,实例化一个BufferQueueConsumer对象,其构造函数在初始化成员变量时,在会直接将前面创建好的 BufferQueueCore 和 mSlots 赋值到  的成员变量mSlots中。

    BufferQueueConsumer::mSlots 是 BufferQueueCore::mSlots的映射/引用,其实就是一个东东!


    Tips:

    BufferQueueProducer和BufferQueueConsumer是BufferQueueCore的友元类,所以可以直接访问其私有成员。


     

    七、小结

    这篇文章主要是讲了一些零碎的概念,这些小的知识点理解后,对于后续理解 生产者 -  缓冲区队列 - 消费者 运行的逻辑十分有帮助。

    下一篇中将会讲解buffer queue的运作流程&buffer是怎样在其中流转的。

     


    必读:

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

     




  • 相关阅读:
    直线联想思维、逆向联想思维、交叉联想思维,设计师一定要具备这几个思维
    输入一行字符串将其中的单词替换成另一单词
    [数据集][目标检测]芒果叶病害数据集VOC+YOLO格式4000张5类别
    如何使用SOLIDWORKS添加装饰螺纹线规格
    什么?漫画居然能免费看全本了,这还不学起来一起做省钱小能手
    Pandas中数据类型的理解
    表单规定输入域的选项列表(html5新元素)
    JSP第二篇 -----JSP浅聊EL表达式第二篇:EL表达式中的运算符
    HTML5+CSS3小实例:侧边导航栏
    【高端电流检测IC储能产品应用方案】耐压45V侧轨的电流检测芯片FP137 应用于电脑电源,开关电源以及多口快充充电器,户外移动电源,适配器,电池充电器等
  • 原文地址:https://www.cnblogs.com/roger-yu/p/16020275.html