系列文章请扫关注公众号!
1、BufferQueue
下面这个图片是Google的官方示例,描述了BufferQueue生产者消费者模型。
Android S 版本引入了BLAST Buffer Queue,BLAST主要解决:
1、应用程序在缓冲区的提交中灵活性不足;2、窗口与应用绘制之间无法做到同步,多进程数据无法做到同步;3、简化 SF 中的模型。
Android S 版本之前
- Producer一般是app,Consumer一般指SurfaceFlinger。
- 应用绘制缓冲区仅能通过 BufferQueue IGBP(IGraphicBufferProducer) 提交;
- 应用窗口Geometry的改变仅能通过事务(Transaction)提交;
- 通过合并事务(Transaction.merge())或延迟事务来更改应用窗口间的Geometry;
- 多进程缓冲区之间无法做到同步。
Android S 或更高版本
- BufferQueue 完全存在于 App 进程,dequeue,queue,acquire,release Buffer 的操作均由 App 进行。
- 应用绘制缓冲区可以通过事务Transaction.setBuffer()进行提交;
- 应用窗口Geometry的改变可以通过BlastBufferQueue进行提交;
- 应用绘制的缓冲区和应用窗口Geometry可以进行同步;
- 多应用绘制的缓冲区之间可以进行同步。
2、BlustBufferQueue初始化
在ViewRootImpl的performTraversals方法中,如果App层使用BLASTBufferQueue,会在relayoutWindow()时,构造new BLASTBufferQueue对象,进而一步步调用到BLASTBufferQueue.cpp的BLASTBufferQueue构造函数。
CreateBufferQueue()函数中构造了BufferQueueCore、IGraphicBufferProducer、BufferQueueConsumer。
从ViewrootImpl到BlastBufferQueue的调用流程大致如下:
3、Consumer的绑定
BLASTBufferQueue::BLASTBufferQueue()构造函数中,在
createBufferQueue(&mProducer, &mConsumer)后,又初始化图形缓冲区消费者
mBufferItemConsumer = new BLASTBufferItemConsumer();
BLASTBufferItemConsumer继承自BufferItemConsumer,BufferItemConsumer继承自ConsumerBase。
创建BLASTBufferItemConsumer时,在ConsumerBase的构造函数中实现了如下功能:
1)将ConsumerBase转换为ConsumerListener。
2)将ConsumerListener封装为ProxyConsumerListener。
3)向Consumer注册回调。
IGraphicBufferConsumer的cosumerConnect方法是一个跨进程调。最终会调用BufferQueueConsumer的connect方法。
这一步也就让 BLASTBufferItemConsumer 建立了对Buffer状态的监听。
调用流程如下:
4、设置图形缓冲区监听器
BLASTBufferItemConsumer 具有监听Buffer所有状态的能力,BBQ对Buffer特定状态的监听离不开 BLASTBufferItemConsumer ,因此,BBQ 继承了两个抽象类 ConsumerBase 与 BufferItemConsumer,分别针对 Buffer 消费状态与生产状态进行监听。
BBQ初始化完成,消费者模型建立完成,由于BBQ动态监听缓冲区的状态,如果有可消费的缓冲区,BBQ会触发缓冲区的事务提交:
如下的调用栈可以看出调用关系:
- Producer的绑定
前面文章《从Activity看surface的创建》中介绍了Surface的创建过程,创建BBQ的流程,在ViewRootImpl.getOrCreateBLASTSurface方法中,创建完BBQ,紧接着会创建Surface对象,直接看Native 对象的构造函数:
Surface的构造函数会传入生产者模型 GraphicBufferProducer,这使Surface对象拥有了操作缓冲区的能力。构造函数中Surface也提供了一系列hook为首的函数,连接到ANativeWindow的函数指针,为的是给EGL模块提供对缓冲区操作的入口。而hook函数会直接调用内部的本地函数。
APP绘制不需要通过hook函数来中转,当上层通过Surface.lockCanvas方法获取画布时会直接调用本地函数函数 Surface::dequeueBuffer。
- 数据流
下图是BufferQueue机制的数据流,根据代码分析下各自调用流程:
Buffer有5中状态,定义如下:
FREE:表示Buffer可以被producer在dequeue时获取。它的slot由BufferQueue持有。当调用dequeueBuffer时,buffer转换为DEQUEUED。
DEQUEUED:表示buffer已被producer从Bufferqueue中取出,但还未QUEUED或CANCEL。当这个Buffer的释放栅栏发出信号(release fence is signaled)时,producer就可以修改Buffer的内容。Slot由producer持有。它通过queueBuffer或attachBuffer可以转换到QUEUED,或通过cancelBuffer或detachBuffer转换成FREE。
QUEUED:表示缓冲区已被Producer填充,并入队供Consumer使用。Buffer内容可以在有限的时间内继续被修改,但在相关的fence 被signaled前不能访问内容。该Slot由BufferQueue持有。它通过acquireBuffer可以转换到ACQUIRED,如果另一个缓冲区以异步模式排队则转换成FREE。
ACQUIRED:表示Buffer已被Consumer获取。与QUEUED一样,在获取栅栏(acquire fence)发出信号(is signaled)之前,Consumer不能访问内容。 Slot由Consumer持有。通过releaseBuffer或detachBuffer转换为FREE。detached buffer 可以通过attachBuffer()进入ACQUIRED状态。
SHARED:表示buffer正以共享缓冲区模式使用。它可以是除FREE外,同时处于其他状态的任何组合。 也可以多次Dequeued、Queued或Acquired 。
6.1 DequeueBuffer
。。。。。。
6.2 QueueBuffer
。。。。。。
6.3 onFrameAvailable和AcquireBuffer
。。。。。。
系列文章请扫关注公众号!