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
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) 图形显示系统 - BufferQueue/BLASTBufferQueue之初识(六)的更多相关文章
- 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) 图形显示系统 - 简单聊聊 SurfaceView 与 BufferQueue的关联(十三)
必读: Android 12(S) 图形显示系统 - 开篇 一.前言 前面的文章中,讲解的内容基本都是从我们提供的一个 native demo Android 12(S) 图形显示系统 - 示例应用( ...
- Android 12(S) 图形显示系统 - 初识ANativeWindow/Surface/SurfaceControl(七)
题外话 "行百里者半九十",是说步行一百里路,走过九十里,只能算是走了一半.因为步行越接近目的地,走起来越困难.借指凡事到了接近成功,往往是最吃力.最艰难的时段.劝人做事贵在坚持, ...
- Android 12(S) 图形显示系统 - 解读Gralloc架构及GraphicBuffer创建/传递/释放(十四)
必读: Android 12(S) 图形显示系统 - 开篇 一.前言 在前面的文章中,已经出现过 GraphicBuffer 的身影,GraphicBuffer 是Android图形显示系统中的一个重 ...
- Android 12(S) 图形显示系统 - Surface 一点补充知识(十二)
必读: Android 12(S) 图形显示系统 - 开篇 一.前言 因为个人工作主要是Android多媒体播放的内容,在工作中查看源码或设计程序经常会遇到调用API: static inline i ...
- Android 12(S) 图形显示系统 - 示例应用(二)
1 前言 为了更深刻的理解Android图形系统抽象的概念和BufferQueue的工作机制,这篇文章我们将从Native Level入手,基于Android图形系统API写作一个简单的图形处理小程序 ...
随机推荐
- Java程序设计(2021春)——第五章输入输出笔记与思考
Java程序设计(2021春)--第五章输入输出笔记与思考 本章概览: 异常处理简介 程序运行时,环境.操作等可能出现各种错误.故障,我们希望程序具有容错能力,给出错误信息.面向对象的程序设计里有异常 ...
- 一次线上服务高 CPU 占用优化实践 (转)
线上有一个非常繁忙的服务的 JVM 进程 CPU 经常跑到 100% 以上,下面写了一下排查的过程.通过阅读这篇文章你会了解到下面这些知识. Java 程序 CPU 占用高的排查思路 可能造成线上服务 ...
- 啥叫IP地址及子网掩码?
啥叫IP地址及子网掩码 ??? 1.IP地址的定义及分类 1.1IP地址的定义 1.2IP地址的分类 2.子网掩码 1.1 互联网上连接的网络设备和计算机都有唯一的地址,此作为该主机在Interne ...
- k8s之Dashboard插件部署及使用
k8s之Dashboard插件部署及使用 目录 k8s之Dashboard插件部署及使用 1. Dashboard介绍 2. 服务器环境 3. 在K8S工具目录中创建dashboard工作目录 4. ...
- go基础——运算符
算数运算符 /* 算术运算符:+,-,*,/,%,++,-- */ a := 10 b := 3 sum := a + b //加减乘类似 fmt.Printf("%d + %d = %d\ ...
- python内置模块之re模块
内容概要 re模块常用方法 findall search match re模块其他方法 split sub subn compile finditer findall 对无名分组优先展示 re实战之爬 ...
- Cobbler 批量安装操作系统
文章目录 环境准备 部署cobbler cobbler语法检查以及排错 问题1 问题2 问题3 问题4 问题5 问题6 问题7 问题8 修改dhcp模板 重启服务,再次检查 镜像配置 镜像导入 kic ...
- Redis学习详解(一):Redis持久化机制之RDB
Redis的持久化机制有两种:RDB持久化和AOF持久化.因为Redis是一个内存数据库,如果没有合适的持久化机制,那么一旦服务器进程退出,服务器中的数据库状态也会消失.本章介绍RDB持久化机制. R ...
- Dubbo基础一之实战初体验
本以为写这个小作文没什么难度的,可是好像并不是.前段时间重心放在驾考科目二,就想着小作文科二考过了再写也不是事,因为都实战过了.今天想着写却发现脑袋里啥都想不起来了,得翻项目和笔记回忆一下.所以还是那 ...
- Dubbo基础之四管理控制台 dubbo-admin
Dubbo提供一个重要功能就是服务治理(SOA governance),什么是服务治理呢?企业为了确保项目顺利完成而实施的过程,需要进行各方面的管理.服务治理就是用来管理SOA的采用和实现的过程. 服 ...