最近总有一个感觉:在不断学习中,越发的感觉自己的无知,自己是不是要从“愚昧之巅”掉到“绝望之谷”了,哈哈哈??
邓宁-克鲁格效应

前面的文章中已经讲解了如何去创建一个Surface,也讲了一些操作Surface的知识,接下来就是如何利用这个Surface进行绘图呢?
在此开始讲解buffer queue的工作流程,看看图形数据是怎样流转的? 图形缓冲区的申请和消费流程是怎样的?有哪些核心类?等等问题在接下来的文章中陆续展开。
这篇文章中,先介绍一些基本概念的东西,帮助后续内容展开打下基础。

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

其中几个比较重要的类,也是后面出场次数比较多的有:
/frameworks/native/libs/gui/include/gui/BufferSlot.h
BufferSlot理解为缓冲槽,一个存放buffer及其信息的地方。这个结构体中主要有如下内容:

我们主要看一下几个成员变量:
关于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) { }
/frameworks/native/libs/gui/include/gui/BufferSlot.h
BufferState用于跟踪记录一个buffer slot(缓冲槽)所处的状态。如下这个类图描述了BufferState中定义的基本内容:

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)的值来进行判断的,如下表格就是各种状态下各个变量的组合情况:

在图形缓冲区队列的逻辑中,有几处队列、数组,我们大概看一看他们代表了什么意思。
/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;
/frameworks/native/libs/gui/include/gui/BufferQueueDefs.h
namespace BufferQueueDefs { typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];} // namespace BufferQueueDefs
/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;
Tips:
mFreeSlots/mFreeBuffers/mUnusedSlots/mActiveBuffers存储的都是int类型的index,根据这个index去mSlots中获取对应的BufferSlot及GraphicBuffer.
我的理解之所以划分出这么多不同的数组,都是为了给 BufferSlot 分类,以便获取 GraphicBuffer 时更加高效。
看器构造函数:
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.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是怎样在其中流转的。

