Android 12(S) 图形显示系统 - BufferQueue的工作流程(八)
题外话
最近总有一个感觉:在不断学习中,越发的感觉自己的无知,自己是不是要从“愚昧之巅”掉到“绝望之谷”了,哈哈哈
邓宁-克鲁格效应

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

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

其中几个比较重要的类,也是后面出场次数比较多的有:
- 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) 图形显示系统 - 开篇

Android 12(S) 图形显示系统 - BufferQueue的工作流程(八)的更多相关文章
- Android 12(S) 图形显示系统 - BufferQueue的工作流程(九)
题外话 Covid-19疫情的强烈反弹,小区里检测出了无症状感染者.小区封闭管理,我也不得不居家办公了.既然这么大把的时间可以光明正大的宅家里,自然要好好利用,八个字 == 努力工作,好好学习 一.前 ...
- Android 12(S) 图形显示系统 - BufferQueue的工作流程(十)
题外话 疫情隔离在家,周末还在努力学习的我 ..... 一.前言 上一篇文章中,有基本讲清楚Producer一端的处理逻辑,最后也留下了一个疑问: Consumer是什么时候来消费数据的?他是自己主 ...
- Android 12(S) 图形显示系统 - BufferQueue的工作流程(十一)
题外话 我竟然已经写了这个系列的十一篇文章了,虽然内容很浅显,虽然内容很枯燥,虽然内容也许没营养,但我为自己的坚持点赞! 一.前言 前面的两篇文章,分别讲解了Producer的处理逻辑和queue b ...
- Android 12(S) 图形显示系统 - BufferQueue/BLASTBufferQueue之初识(六)
题外话 你有没有听见,心里有一声咆哮,那一声咆哮,它好像在说:我就是要从后面追上去! 写文章真的好痛苦,特别是自己对这方面的知识也一知半解就更加痛苦了.这已经是这个系列的第六篇了,很多次都想放弃了,但 ...
- Android 12(S) 图形显示系统 - 解读Gralloc架构及GraphicBuffer创建/传递/释放(十四)
必读: Android 12(S) 图形显示系统 - 开篇 一.前言 在前面的文章中,已经出现过 GraphicBuffer 的身影,GraphicBuffer 是Android图形显示系统中的一个重 ...
- Android 12(S) 图形显示系统 - 简单聊聊 SurfaceView 与 BufferQueue的关联(十三)
必读: Android 12(S) 图形显示系统 - 开篇 一.前言 前面的文章中,讲解的内容基本都是从我们提供的一个 native demo Android 12(S) 图形显示系统 - 示例应用( ...
- Android 12(S) 图形显示系统 - 初识ANativeWindow/Surface/SurfaceControl(七)
题外话 "行百里者半九十",是说步行一百里路,走过九十里,只能算是走了一半.因为步行越接近目的地,走起来越困难.借指凡事到了接近成功,往往是最吃力.最艰难的时段.劝人做事贵在坚持, ...
- Android 12(S) 图形显示系统 - 示例应用(二)
1 前言 为了更深刻的理解Android图形系统抽象的概念和BufferQueue的工作机制,这篇文章我们将从Native Level入手,基于Android图形系统API写作一个简单的图形处理小程序 ...
- Android 12(S) 图形显示系统 - 基本概念(一)
1 前言 Android图形系统是系统框架中一个非常重要的子系统,与其它子系统一样,Android 框架提供了各种用于 2D 和 3D 图形渲染的 API供开发者使用来创建绚丽多彩的应用APP.图形渲 ...
随机推荐
- Apache——网页优化与安全
Apache--网页优化与安全 1.Apache 网页优化概述 2.网页压缩 3.网页缓存 4.隐藏版本信息 5.Apache 防盗链 1.Apache 网页优化概述: 企业中,部署Apache后只采 ...
- 使用rsync+inotify实现/www目录实时同步
一.实现bak-server 1.1安装rsync # yum -y install rsync 1.2修改配置文件 # vi /etc/rsyncd.conf #添加下面内容 uid=test gi ...
- python基础语法_字符串编码
Python常用字符编码 http://www.cnblogs.com/schut/p/8406897.html Python常见字符编码间的转换 在字符串写入文件时,有时会因编码问题导致无法 ...
- v78.01 鸿蒙内核源码分析(消息映射篇) | 剖析LiteIpc(下)进程通讯机制 | 百篇博客分析OpenHarmony源码
百篇博客分析|本篇为:(消息映射篇) | 剖析LiteIpc(下)进程通讯机制 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析( ...
- Spring Boot run()方法剖析
Spring Boot自动配置部分重点介绍了相关注解,关于main中调用的run方法并没有阐述过.run方法的作用是什么呢?只有注解没有main里的run方法Spring Boot工程就好比身体个方面 ...
- Spring Cloud Feign 如何使用对象参数
概述 Spring Cloud Feign 用于微服务的封装,通过接口代理的实现方式让微服务调用变得简单,让微服务的使用上如同本地服务.但是它在传参方面不是很完美.在使用 Feign 代理 GET 请 ...
- 【FAQ】接入HMS Core应用内支付服务过程中一些常见问题总结
HMS Core应用内支付服务(In-App Purchases,IAP)为应用提供便捷的应用内支付体验和简便的接入流程.开发者的应用集成IAP SDK后,调用IAP SDK接口,启动IAP收银台,即 ...
- 什么,有狗快跑!慢着,这次手把手教你怎么过安全狗!(sql注入篇)
前言 在记忆里上次绕安全狗还是在上次,开开心心把自己之前绕过狗的payload拿出来,发现全部被拦截了,事情一下子就严肃起来了,这就开整. 环境 本次环境如下sqli-lab的sql注入靶场 网站安全 ...
- 安装好的pycharm修改代码存储路径
安装好pycharm的时候,第一次点开pycharm没有配置好,导致代码存放的路径是默认的.但是现在想把路径改成自己的路径怎么办? 首先,pycharm->file->settings-& ...
- c# 编程学习(二)
标识符是对程序中的各个元素进行标识的名称. 只能使用字母(大写和小写).数字和下划线 标识符必须以字母或下划线开头 变量是容纳值的存储位置.可将变量想象成容纳临时信息的容器 ...