本文基于Android 15梳理。
前言
Android图形架构中,对所有图形数据流的处理,是以"生产者-消费者"模式实现,并通过一个图形数据缓冲队列,实现图形数据的传递。
- 图形流生产者:指生成Graphic Buffer内容的组件,如OpenGL ES、Canvas、CameraPreview、多媒体视频解码器;
- 图形流消费者:指对生产者提供的Graphic Buffer进行使用的组件,一般即指surfaceflinger,有些场景下,也可以是其他应用;
- 图形数据缓冲区队列:作为Android图形组件的粘合剂,用来在生产者-消费者之间进行Graphic Buffer的传递,Graphic Buffer的移动必须在该队列中进行。
这个图形数据缓冲区队列便是本篇中的主角前身——BufferQueue。
在BufferQueue机制中,定义了BufferQueue类作为Graphic Buffer队列的抽象和封装,同时定义了三个类:
- BufferQueueCore:Buffer队列实现类,内部定义了多个Buffer数组和列表,负责Graphic Buffer的传递、状态管理;
- IGraphicBufferProducer:IPC接口,用于Buffer Queue和图形流生产者连接;
- IGraphicBufferConsumer:IPC接口,用于Buffer Queue和图形流消费者连接。
在Android P及以前版本中,图层渲染合成部分对Buffer Queue的机制使用方式是集成在了surfaceflinger进程Layer中,在初始化BufferQueueLayer时创建BufferQueue,并将IGraphicBufferProducer接口对象传递给了Surface,将IGraphicBufferConsumer接口对象传递给了BufferLayerConsumer。
这种实现方式缺点显而易见:
- sufaceflinger进程变得臃肿:Layer中包含了太多获取Buffer过程的操作,而不是直接使用Buffer;
- Layer中接收数据的方式不一:Graphic Buffer通过Buffer Queue队列获得,其他几何属性通过Transaction提交;
- 几何属性和Buffer同步可能存在延时:由于传递方式的不同,某些场景下Graphic Buffer和几何属性需要同时更新时,可能存在无法一次性处理或延时的问题;
- 多个进程间无法做到帧同步:在一些需要两个进程同步执行动画时,无法做到同一帧提交不同进程的Buffer。
因此,在此后的版本中,AOSP开始尝试逐步将BufferQueue从Layer中剥离出去,并在Android S上,所有应用端图层绘制合成彻底废弃Buffer Queue机制,采用了新的机制——BLAST Buffer Queue机制。
BLAST Buffer Queue机制完全填补了Buffer Queue机制的缺点:
- BufferQueue的创建放在了业务进程,surfaceflinger中只接受Buffer,同时所有图层属性的提交都通过Transaction进行,大大减轻了surfaceflinger的负担;
- 支持Transaction的合并操作,多个Transaction可以合并为一个提交给surfaceflinger进程,从而可以保证Buffer的提交和几何属性的提交都可在同一帧完成;
- 支持多进程间的协同能力(BLAST SyncEngine),可以对Transaction跨进程传递,携带不同进程的Buffer一起提交给surfaceflinger,实现进程间的帧同步。
"BLAST"的正式含义AOSP中没有具体给出,个人认为应该是"Buffer Layer All Sync by Transaction",即Layer属性全部由Transaction进行提交和更新。
BBQ架构中Graphic Buffer流表示如下图所示:
本篇文章中,对BLAST Buffer Queue架构的实现原理和基本概念进行总结梳理。
一、BBQ架构
BLAST Buffer Queue机制相比Buffer Queue机制,主要在行为和能力上发生了变化:
- BufferQueue在应用进程创建;
- Graphic Buffer的传递方式发生变化;
- 增加了跨进程同步Buffer的能力。
其核心组件和本质并没有太大变化,主要还是由三部分组成:
- 生产者接口:当Surface需要更新显示内容时,生产者接口会为Surface从Buffer队列中提供来自Gralloc分配的Graphic Buffer,Surface获得Graphic Buffer后便可给到GPU/CPU进行绘制操作,并在完成绘制后继续通过生产者接口将Graphic Buffer放入Buffer队列;
- 消费者接口:当Surface完成绘制操作并且Graphic Buffer重新入队后,会通过消费者接口将Graphic Buffer传递给surfaceflinger进程,对Graphic Buffer进行实际的消费,完成图层的合成与显示。
- BBQ核心组建:统一维护一个实际的Graphic Buffer队列,管理Graphic Buffer在生产者和消费者间的移动,同时也负责整个Buffer队列的参数配置和更新。
类图关系如下:
1.1、生产者接口
1.1.1、IGraphicBufferProducer
IGraphicBufferProducer接口定义了BBQ架构中GraphicBuffer生产者类的IPC接口和通用方法,是BBQ中生产者类的最顶层接口。
1.1.2、BufferQueueProducer
BufferQueueProducer类实现了IGraphicBufferProducer接口,除了重写IGraphicBufferProducer接口定义的方法,还定义了和Consumer、BufferQueueCore等BBQ架构中其他组件产生依赖和交互的方法或对象:
// frameworks/native/include/gui/BufferQueueProducer.h
class BufferQueueProducer : public BnGraphicBufferProducer,
private IBinder::DeathRecipient {
......
// 当Buffer队列中没有可用Buffer时,通过该方法进入等待状态
status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, std::unique_lock<std::mutex>& lock,
int* found) const;
// BufferQueueCore对象
sp<BufferQueueCore> mCore;
// Buffer队列,Buffer槽(BufferSlot数组)
BufferQueueDefs::SlotsType& mSlots;
};
1.1.3、BBQBufferQueueProducer
BBQBufferQueueProducer类继承于BufferQueueProducer,它主要是为了实现异步执行IProducerListener接口的回调方法而定义的包裹类。它定义在BLASTBufferQueue类中:
// frameworks/native/libs/gui/BLASTBufferQueue.cpp
class BBQBufferQueueProducer : public BufferQueueProducer {
public:
BBQBufferQueueProducer(const sp<BufferQueueCore>& core, wp<BLASTBufferQueue> bbq)
: BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/),
mBLASTBufferQueue(std::move(bbq)) {}
status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp,
QueueBufferOutput* output) override {
// 如果listener为空,则将listener传递给BufferQueueProducer
if (!listener) {
return BufferQueueProducer::connect(listener, api, producerControlledByApp, output);
}
// 如果listener不为空,则会将listener包裹成AsyncProducerListener后传递给BufferQueueProducer
return BufferQueueProducer::connect(new AsyncProducerListener(listener), api,
producerControlledByApp, output);
}
......
};
Surface创建后,会通过IGraphicBufferProducer->connect()方法将Surface和BufferQueueProducer进行连接。
1.1.4、IProducerListener
IProducerListener接口是BBQ向生产者组件通知Buffer事件的接口,主要有两个作用:
- BBQ通知BufferQueueProducer事件,BufferQueueProducer中可将事件通过IProducerListener通知给Client端;
- BufferQueueProducer中监听Client端进程是否死亡。
它也是通过IGraphicBufferProducer->connect()方法由Buffer的使用方向BBQ中完成注册。
在Surface中,会在跟BufferQueueProducer连接时,传入一个StubProducerListener对象:
// frameworks/native/libs/gui/Surface.cpp
int Surface::connect(int api) {
static sp<IProducerListener> listener = new StubProducerListener();
return connect(api, listener);
}
StubProducerListener类是一个空的实现类,其作用是Server端在BufferQueueProducer中对Client端进程的监听。
1.2、消费者接口
1.2.1、IGraphicBufferConsumer
IGraphicBufferConsumer接口对应于IGraphicBufferProducer接口,定义了BBQ架构中GraphicBuffer生产者类的IPC接口和通用方法。
IGraphicBufferProducer通过queueBuffer将GraphicBuffer放入Buffer队列后,IGraphicBufferConsumer便可通过acquireBuffer操作从Buffer队列中获取GraphicBuffer的所有权,并逐步将GraphicBuffer传递给surfaceflinger进行合成与显示。
1.2.2、BufferQueueConsumer
BufferQueueConsumer类实现了IGraphicBufferConsumer接口,是BBQ中读取GraphicBuffer的实际Consumer对象,内部持有一个BufferQueueCore对象,可以用来对BBQ进行配置:
// frameworks/native/libs/gui/include/gui/BufferQueueConsumer.h
class BufferQueueConsumer : public BnGraphicBufferConsumer {
......
private:
sp<BufferQueueCore> mCore;
// This references mCore->mSlots. Lock mCore->mMutex while accessing.
BufferQueueDefs::SlotsType& mSlots;
// This is a cached copy of the name stored in the BufferQueueCore.
// It's updated during setConsumerName.
String8 mConsumerName;
}; // class BufferQueueConsumer
1.2.3、IConsumerListener
IConsumerListener是用于BBQ向消费者组件通知Buffer操作事件的接口。比如:当BufferQueueProducer执行完queueBuffer()后,便通过IConsumerListener::onFrameAvailable()通知消费者组件从Buffer队列中获取可用Buffer。
1.2.4、ConsumerBase
ConsumerBase实现了IConsumerListener接口,是消费者组件中处理通用任务的基类。
BBQ不会和BufferQueueConsumer直接进行交互,而是通过ConsumerBase向BufferQueueConsumer发起调用,ConsumerBase在初始化时会传入BufferQueueConsumer对象:
// frameworks/native/libs/gui/ConsumerBase.cpp
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
mAbandoned(false),
mConsumer(bufferQueue),
mPrevFinalReleaseFence(Fence::NO_FENCE) {
wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
// BBQ和mConsumer进行连接
status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
......
}
使用ConsumerBase时,一般会定义一个子类跟BufferQueueConsumer类交互,如在BBQ中定义了BufferItemConsumer类,surfaceflinger中定义了FrameBufferSurface类用于Client合成过程中获取GraphicBuffer。
1.2.5、BufferItemConsumer
BufferItemConsumer类是ConsumerBase的子类,在BBQ架构中作为BBQ和BufferQueueConsumer进行交互的中间层。
// frameworks/base/libs/hostgraphics/gui/BufferItemConsumer.h
class BufferItemConsumer : public ConsumerBase {
public:
BufferItemConsumer(
const sp<IGraphicBufferConsumer>& consumer,
uint64_t consumerUsage,
int bufferCount,
bool controlledByApp) : mConsumer(consumer) {
}
......
};
1.2.6、BLASTBufferItemConsumer
BLASTBufferItemConsumer是BufferItemConsumer的子类,主要作用是增加了一些帧数据的统计的方法和对象。
1.3、BBQ核心
1.3.1、BLASTBufferQueue
BLASTBufferQueue是BBQ架构的抽象,也是生产者和消费者组组件的创建者。当初始化一个BLASTBufferQueue对象后,便意味着创建了一个Buffer队列、BufferQueueProducer对象和BufferQueueConsumer对象。
应用进程中,在ViewRootImpl中创建BLASTBufferQueue对象,并返回Surface对象:
// frameworks/base/core/java/android/view/ViewRootImpl.java
void updateBlastSurfaceIfNeeded() {
......
// 创建BLASTBufferQueue对象
mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
// 从mBlastBufferQueue中获取Surface对象
Surface blastSurface = mBlastBufferQueue.createSurface();
// Only call transferFrom if the surface has changed to prevent inc the generation ID and
// causing EGL resources to be recreated.
mSurface.transferFrom(blastSurface);
......
}
1.3.2、BufferQueueCore
BufferQueueCore是Buffer队列真正的实现之处,它负责Graphic Buffer的所有权转移、Buffer队列状态管理、以及队列参数配置。内部定义了多个Buffer索引列表和一个BufferSlot对象数组用来存放GraphicBuffer的索引以及GraphicBuffer对象。
BufferQueueCore对象创建完成后,会作为参数进行BufferQueueProducer和BufferQueueConsumer的创建,
BufferQueueProducer和BufferQueueConsumer中都可以通过BufferQueueCore对象获取Graphic Buffer,以及对Buffer队列配置进行更新。
二、BBQ内部队列结构
1.1、Graphic Buffer的状态周期
BBQ中Graphic Buffer根据其所有权持有关系和流转阶段,共定义了4种状态,状态流转周期如下图所示:
- BBQ在创建时,会预先向Gralloc申请一定数量的Buffer,此时Buffer状态为
FREE状态; - 当生产者需要Buffer时,会通过IGBP接口向Buffer Queue请求空闲Buffer,并指定其宽、高、pixel格式、flag等属性。这步通过
dequeueBuffer()方法进行,操作成功后Buffer的所有权将给到生产者,此时Buffer状态变为DEQUEUED状态; - 申请到空闲Buffer后,生产者端会对Buffer进行绘制、填充,绘制完毕后重新放入队列中,并通知消费者进行消费。这步通过
queueBuffer()方法进行,操作成功后Buffer的所有权回到Buffer Queue中,此时Buffer状态变为QUEUED状态; - 消费者端收到消费回调后,会通过IGBC接口向Buffer Queue中获取
QUEUED状态的Buffer,并将Buffer发送给surfaceflinger。这一步通过acquireBuffer()方法进行,操作成功后Buffer的所有权将给到消费者,此时Buffer状态变为ACQUIRED状态; - surfaceflinger中获得新的Buffer后,不再需要上一帧Buffer,会回调给Buffer Queue中,并通过IGBC接口将Buffer重新放入队列中。这步通过
releaseBuffer()方法进行,操作成功后Buffer所有权回到Buffer Queue中,Buffer状态重新变为FREE状态。
在应用进程中,除releaseBuffer由binder线程释放外,其他三个方法都执行在RenderThread中执行。
1.2、Buffer队列数据结构
在整个状态变化和Buffer所有权的转移过程中,不会发生数据的移动和拷贝,这跟系统内架构存实现原理有关。此外由于移动大量Graphic Buffer数据很低效,所以在跟surfaceflinger进程的传递过程中,采用Graphic Buffer句柄的方式进行传递。
BBQ中将Graphic Buffer放在Buffer槽(BufferSlot)中,在Producer和Consumer的移动过程中,只传递BufferSlot的索引。
在BufferQueueCore中,定义了多个列表来实现Buffer在Producer和Consumer间的移动,图示描述如下:
这里结合代码,对BufferSlot和BufferItem进行详细了解,它们贯穿整个BBQ流程中。
1.2.1、BufferSlot
BufferSlot表示一个"Buffer槽",是Buffer在BBQ内部Producer和Consumer之间传递的基本单位,它封装了GraphicBuffer、BufferState、Fence、EGLDisplay等内容,管理GraphicBuffer的状态。
// frameworks/native/libs/gui/include/gui/BufferSlot.h
struct BufferSlot {
.......
// GraphicBuffer对象,初始化时为nullptr,allocateBuffer过程中会对它赋值
sp<GraphicBuffer> mGraphicBuffer;
// EGLDisplay对象,用于创建EGLSyncKHR
EGLDisplay mEglDisplay;
// BufferState用于描述该BufferSlot状态,如FREE、DEQUEUED、QUEUED、ACQUIRED、SHARED状态都由它来描述
BufferState mBufferState;
// 用于标记producer是否对该BufferSlot进行过requestBuffer()操作
bool mRequestBufferCalled;
// 帧计数器,每次queueBuffer时会递增+1,可以理解为每queueBuffer成功一次,该值+1
uint64_t mFrameNumber;
// EGLSyncKHR用于同步EGL和OpenGL/Vulkan之间的操作,可以确保进行渲染图形或交换缓冲区
// 时,所有图形命令已经完成
EGLSyncKHR mEglFence;
// Fence对象,Fence主要用于处理GPU和CPU之间的Buffer同步问题
sp<Fence> mFence;
// 用于描述该BufferSlot是否已经被consumer进行过acquireBuffer操作
bool mAcquireCalled;
// 用于描述该BufferSlot的mGraphicBuffer是否进行重新分配
// 该值为true时说明发生过reallocate操作,会在dequeuebuffer时,设置BUFFER_NEEDS_REALLOCATION标记,
// 通知producer防止使用过时的GraphicBuffer。
// 重新申请Buffer时,BufferQueueCore::clearBufferSlotLocked()中将该值设置为true
// 添加BUFFER_NEEDS_REALLOCATION后,在dequeueBuffer/attachBuffer时重置为false
bool mNeedsReallocation;
};
BBQ中定义了一个BufferSlot数组,这个数组便是实际的Buffer Queue:
// frameworks/native/include/gui/BufferQueueDefs.h
namespace BufferQueueDefs {
// SlotsType表示一个包含NUM_BUFFER_SLOTS个BufferSlot 元素的数组
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
} // namespace BufferQueueDefs
NUM_BUFFER_SLOTS值为64,说明一个BBQ队列中最多只能申请64个Graphic Buffer。
1.2.2、BufferState
BufferState用于记录BufferSlot的状态,通过四个属性描述BufferSlot的五种状态:
// frameworks/native/libs/gui/include/gui/BufferSlot.h
struct BufferState {
// 当前BufferSlot处于DEQUEUED状态的个数
uint32_t mDequeueCount;
// 当前BufferSlot处于QUEUED状态的个数
uint32_t mQueueCount;
// 当前BufferSlot处于ACQUIRED状态的个数
uint32_t mAcquireCount;
// 该BufferSlot是否为Share Buffer模式
bool mShared;
....
};
其状态跟属性对应关系如下表:
| mShared | mDequeueCount | mQueueCount | mAcquireCount | 含义 | |
|---|---|---|---|---|---|
| FREE | FALSE | 0 | 0 | 0 | Buffer处于空闲状态,可以被Producer进行dequeue操作 |
| DEQUEUED | FALSE | 1 | 0 | 0 | Buffer处于"出队"状态,已经被Producer进行了dequeue操作,但还没有进行queue操作 |
| QUEUED | FALSE | 0 | 1 | 0 | Buffer处于"入队"状态,已经被Producer填充且重新入对,等待Consumer消费 |
| ACQUIRED | FALSE | 0 | 0 | 1 | Buffer已经被Consumer获取,用于对buffer内容进行合成,完成并释放后,重新恢复FREE状态 |
| SHARED | TRUE | any | any | any | Buffer以共享方式使用,可以同时进行dequeue、queue、acquired等操作 |
之所以以引用计数的方式标记状态,是因为在Shared Buffer mode状态时,可以同时有多个状态。
1.2.3、BufferItem
BufferItem是Buffer队列mCore->mQueue的元素,它是真正入队的数据,它封装了所有来自客户端输入的图形数据,传递给surfaceflinger的数据基本也全都是BufferItem中的属性。
// frameworks/native/libs/gui/include/gui/BufferItem.h
class BufferItem : public Flattenable<BufferItem> {
......
// 引用自BufferSlot中的mGraphicBuffer对象
sp<GraphicBuffer> mGraphicBuffer;
// fence对象,用于CPU/GPU间GB状态的同步
sp<Fence> mFence;
// Fence的包裹类,可记录变为有信号状态的时间戳
std::shared_ptr<FenceTime> mFenceTime{FenceTime::NO_FENCE};
// 当前GraphicBuffer对象的裁剪区域
Rect mCrop;
// 当前GraphicBuffer的方向标记,值参考window.h中的NATIVE_WINDOW_TRANSFORM_*
uint32_t mTransform;
// 当前GraphicBuffer的缩放模式,值参考window.h中的NATIVE_WINDOW_SCALING_*
uint32_t mScalingMode;
// queueBuffer时刻的时间戳
int64_t mTimestamp;
// 表示mTimestamp是否为自动生成
bool mIsAutoTimestamp;
// 当前GraphicBuffer的dataspace
android_dataspace mDataSpace;
// 当前GraphicBuffer的HDR元数据
HdrMetadata mHdrMetadata;
// 当前GraphicBuffer的帧数,在queueBuffer时标记
uint64_t mFrameNumber;
// 当前BufferItem所使用GraphicBuffer的slot索引
int mSlot;
// 是否可丢弃,用于非阻塞模式的dequeueBuffer操作时
bool mIsDroppable;
// 当前Buffer已经执行acquiredBuffer操作
bool mAcquireCalled;
// 转换方向标记,表示是否需要用屏幕转置矩阵进行变换
bool mTransformToDisplayInverse;
// Surface内容发生变化的区域
Region mSurfaceDamage;
// 共享模式时,Consumer是否可以在不用等待Buffer可用时就可以获取下一帧
bool mAutoRefresh;
// 表示该Buffer是否被Producer执行过queuedBuffer操作
bool mQueuedBuffer;
// 表示是否已经是过期的Buffer
bool mIsStale;
// Producer API,表示Buffer的来源
int mApi;
};
三、BBQ使用流程
BBQ的使用过程可分解为四步:
- 创建BBQ;
- Surface和BBQ连接;
- 生产和消费Graphic Buffer;
- 销毁BBQ。
3.1、创建BBQ
Java层可通过BLASTBufferQueue类初始化BBQ。在应用进程中,BBQ的创建是在ViewRootImpl中进行:
// frameworks/base/core/java/android/view/ViewRootImpl.java
void updateBlastSurfaceIfNeeded() {
......
// 创建BBQ对象
mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
// 从BBQ获取Surface对象
Surface blastSurface = mBlastBufferQueue.createSurface();
}
system_server中也可以直接创建BBQ。
创建过程中,会通过JNI层进入Native层进行BLASTBufferQueue对象及其组件的初始化操作。
Native层创建BBQ通过SurfaceControl::getSurface()方法创建:
// frameworks/native/libs/gui/SurfaceControl.cpp
sp<Surface> SurfaceControl::getSurface()
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == nullptr) {
return generateSurfaceLocked();
}
return mSurfaceData;
}
sp<Surface> SurfaceControl::generateSurfaceLocked()
{
uint32_t ignore;
auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow |
ISurfaceComposerClient::eOpaque);
// 创建SurfaceControl对象
mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
flags, mHandle, {}, &ignore);
// 创建BBQ对象
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;
}
最终会创建一个"bbq-adapter"命名的BBQ。
下面从BBQ构造方法开始,看下BBQ中各个组件的初始化流程。
// frameworks/native/libs/gui/BLASTBufferQueue.cpp
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame)
: mSurfaceControl(nullptr), // mSurfaceControl用于和sf中的Layer关联
// Surface宽高,也是申请GraphicBuffer时的宽高
mSize(1, 1),
mRequestedSize(mSize),
mFormat(PIXEL_FORMAT_RGBA_8888),
// 用于跨进程同步帧,用于监听sf中Transaction的commit操作是否执行
mTransactionReadyCallback(nullptr),
// 用于跨进程同步帧,mSyncTransaction不为空时,会将Transaction传递给VRI进行apply
mSyncTransaction(nullptr),
mUpdateDestinationFrame(updateDestinationFrame) {
// 创建BufferQueue队列
createBufferQueue(&mProducer, &mConsumer);
// 设置dequeueBuffer的超时时间
mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());
// 设置同时处于DEQUEUED状态buffer的最大个数,默认为2
mProducer->setMaxDequeuedBufferCount(2);
// 创建BufferItemConsumer对象
mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
GraphicBuffer::USAGE_HW_COMPOSER |
GraphicBuffer::USAGE_HW_TEXTURE,
1, false, this);
static std::atomic<uint32_t> nextId = 0;
mProducerId = nextId++;
// 设置Consumer name
mName = name + "#" + std::to_string(mProducerId);
auto consumerName = mName + "(BLAST Consumer)" + std::to_string(mProducerId);
// "QueuedBuffer - "用于trace分析
mQueuedBufferTrace = "QueuedBuffer - " + mName + "BLAST#" + std::to_string(mProducerId);
mBufferItemConsumer->setName(String8(consumerName.c_str()));
// 向Consumer设置FrameAvailable回调,当Producer端完成queueBuffer时,通过该回调通知Consumer
mBufferItemConsumer->setFrameAvailableListener(this);
// 从sf进程获取acquirebuffer的最大个数
ComposerServiceAIDL::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
// 设置设置同时处于ACQUIRED状态buffer的最大个数
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
mNumAcquired = 0;
mNumFrameAvailable = 0;
// 设置TransactionCompletedListener监听
TransactionCompletedListener::getInstance()->addQueueStallListener(
[&](const std::string& reason) {
std::function<void(const std::string&)> callbackCopy;
{
std::unique_lock _lock{mMutex};
callbackCopy = mTransactionHangCallback;
}
if (callbackCopy) callbackCopy(reason);
},
this);
}
在BBQ构造方法内部,就会对BufferQueueCore、BufferQueueProducer和BufferQueueConsumer全部完成创建,并对BBQ中各个状态的最大Buffer数完成设置。
在createBufferQueue()方法中,会完成IGraphicBufferQueueProducer、IGraphicBufferQueueConsumer相关对象的初始化:
// frameworks/native/libs/gui/BLASTBufferQueue.cpp
void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer) {
// 创建BufferQueueCore对象
sp<BufferQueueCore> core(new BufferQueueCore());
// 创建BBQBufferQueueProducer对象
sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core, this));
// 创建BufferQueueConsumer对象
sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
consumer->setAllowExtraAcquire(true);
*outProducer = producer;
*outConsumer = consumer;
}
3.1.1、创建BufferQueueCore对象
BufferQueueCore是Buffer队列实现之处,同时定义了接口允许Producer对象和Consumer对象进行配置参数的调整,构造方法如下:
// frameworks/native/libs/gui/BufferQueueCore.cpp
BufferQueueCore::BufferQueueCore()
: mMutex(),
// Buffer队列是否已经废弃,Consumer断开连接后将变为废弃状态
mIsAbandoned(false),
// 表示与Buffer队列连接的Consumer是否可以由应用自己控制,一般都为false
mConsumerControlledByApp(false),
// Consumer名称
mConsumerName(getUniqueName()),
// IConsumerListener监听对象,在Consumer连接时由Consumer对象设置
mConsumerListener(),
// Consumer指定的GraphicBuffer的使用标记
mConsumerUsageBits(0),
// Consumer是否开始处理protected buffer
mConsumerIsProtected(false),
// 表示Producer API,在Producer连接时设置,默认NO_CONNECTED_API
mConnectedApi(NO_CONNECTED_API),
// 用于Cliend端进程死亡监听,也是一个IProducerListener对象
mLinkedToDeath(),
// IProducerListener对象,用于通知Client端Buffer相关事件
mConnectedProducerListener(),
// 是否允许回调IProducerListener::onBufferReleased()方法
mBufferReleasedCbEnabled(false),
// BufferSlot对象数组,就是"Buffer Queue",在Producer和Consumer之间传递Buffer所有权的基本单位
mSlots(),
// BufferItem列表,用于保存已经完成绘制操作后入队的GraphicBuffer
mQueue(),
// 索引值列表,保存所有未绑定GraphicBuffer的空闲BufferSlot在mSlots列表中的索引值
mFreeSlots(),
// 索引值列表,保存所有绑定了GraphicBuffer的空闲BufferSlot在mSlots列表中的索引值
mFreeBuffers(),
// 索引值列表,保存所有
mUnusedSlots(),
// 索引值列表,保存所有非空闲状态BufferSlot在mSlots列表中的索引值
mActiveBuffers(),
// std::condition_variable锁,用于在同步模式下dequeueBuffer时等待空闲Buffer
mDequeueCondition(),
// 表示BufferQueueProducer在dequeueBuffer时BBQ处理模式,默认为false(阻塞模式),
// 只有当Producer和Consumer都由应用端控制时,该值为true(非阻塞模式),
// 即没有空闲Buffer时不会等待,而是直接返回
mDequeueBufferCannotBlock(false),
// 表示BufferQueueProducer在queueBuffer时BBQ处理模式,默认为false(非丢弃模式),
// 只有当Producer和Consumer都由应用端控制时,该值为true(丢弃模式),
// 即如果有未消费Buffer,会直接丢弃掉
mQueueBufferCanDrop(false),
mLegacyBufferDrop(true),
// 默认Buffer格式,由Consumer设置,Producer在dequeueBuffer时如果未指定格式,默认使用该值
mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
// Buffer的默认宽高,由Consumer设置,Producer在dequeueBuffer时如果未指定宽高,默认使用该值
mDefaultWidth(1),
mDefaultHeight(1),
// Buffer的默认DataSpace,由Consumer设置,Producer在queueBuffer时如果未指定,默认使用该值
mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
// 队列最大可申请的Buffer数
mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
// Consumer最多能acquireBuffer的个数,默认为1,可通过Consumer设置
mMaxAcquiredBufferCount(1),
// Producer最多能dequeueBuffer的个数, 默认为1,可通过Producer设置
mMaxDequeuedBufferCount(1),
// 当发生queueBuffer后,该值将变为true
mBufferHasBeenQueued(false),
// 帧数统计,每次queueBuffer后+1
mFrameCounter(0),
// 屏幕方向提示,由Consumer设置
mTransformHint(0),
// 表示producer正在进行分配新的GraphicBuffer,此时不允许对任何队列进行修改
mIsAllocating(false),
// 条件锁,当mIsAllocating为false后唤醒,用于分配Graphic Buffer过程
mIsAllocatingCondition(),
// 是否允许分配Buffer
mAllowAllocation(true),
// 用于记录最近一次dequeueBuffer返回Buffer的年龄,自上次queueBuffer后经过的帧数,总帧数 - 该Buffer帧数
mBufferAge(0),
// 由Producer设置,在attachBuffer操作时跟Buffer::mGenerationNumber做匹配
mGenerationNumber(0),
// 该BBQ是否开启了异步模式
mAsyncMode(false),
// shareBuffer模式
mSharedBufferMode(false),
mAutoRefresh(false),
mSharedBufferSlot(INVALID_BUFFER_SLOT),
mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
HAL_DATASPACE_UNKNOWN),
mLastQueuedSlot(INVALID_BUFFER_SLOT),
mUniqueId(getUniqueId()),
mAutoPrerotation(false),
mTransformHintInUse(0) {
// 填充mFreeSlots
int numStartingBuffers = getMaxBufferCountLocked();
for (int s = 0; s < numStartingBuffers; s++) {
mFreeSlots.insert(s);
}
// 填充mUnusedSlots
for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
s++) {
mUnusedSlots.push_front(s);
}
}
3.1.2、创建IGraphicBufferProducer对象
BBQ中,IGraphicBufferProducer的实现类是BufferQueueProducer,其构造方法如下:
// frameworks/native/libs/gui/BufferQueueProducer.cpp
BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
bool consumerIsSurfaceFlinger) :
// BufferQueueCore对象
mCore(core),
// BufferSlot对象数组,通过该数组获取BufferSlot及其绑定的GraphicBuffer的所有权
mSlots(core->mSlots),
// Consumer名称
mConsumerName(),
// 指定Buffer队列中Buffer的旋转方向,除Camera相关场景外,该值一般不会使用到
mStickyTransform(0),
// Consumer是否为sf
mConsumerIsSurfaceFlinger(consumerIsSurfaceFlinger),
// 最近一次入队Buffer的acquire Fence
mLastQueueBufferFence(Fence::NO_FENCE),
// 最近一次入队Buffer的Transform值
mLastQueuedTransform(0),
// 跟CallbackTicket用于保证onFrame* 回调方法的顺序
mCallbackMutex(),
mNextCallbackTicket(0),
mCurrentCallbackTicket(0),
mCallbackCondition(),
// dequeueBuffer和attachBuffer的等待空闲Buffer的Block时长,
// 当队列中没有空闲Buffer时,dequeueBuffer会进入wait状态,直到有空闲Buffer或者到达该timeout,
// -1表示永久等待
mDequeueTimeout(-1),
// 表示是否在dequeueBuffer时等待allocatBuffer完成
mDequeueWaitingForAllocation(false) {
}
3.1.3、创建IGraphicBufferConsumer对象
IGraphicBufferConsumer的实现类是BufferQueueConsumer,其构造方法如下:
// frameworks/native/libs/gui/BufferQueueConsumer.cpp
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
mCore(core),
mSlots(core->mSlots),
mConsumerName() {}
3.1.4、创建ConsumerBase对象
BBQ中ConsumerBase的实现类是BufferItemConsumer,在完成Producer和Consumer对象创建后,接着便会创建
BufferItemConsumer对象,其构造方法如下:
// frameworks/native/libs/gui/BufferItemConsumer.cpp
BufferItemConsumer::BufferItemConsumer(
const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
int bufferCount, bool controlledByApp) :
ConsumerBase(consumer, controlledByApp)
{
// 设置GraphicBuffer usage标记
status_t err = mConsumer->setConsumerUsageBits(consumerUsage);
// 设置acquireBuffer最大个数
if (bufferCount != DEFAULT_MAX_BUFFERS) {
err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
}
}
ConsumerBase构造方法如下:
// frameworks/native/libs/gui/ConsumerBase.cpp
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
// BBQ队列是否已经废弃
mAbandoned(false),
// IGraphicBufferConsumer对象
mConsumer(bufferQueue),
// 上一次释放Buffer时对应的release Fence对象
mPrevFinalReleaseFence(Fence::NO_FENCE) {
mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
// 创建ProxyConsumerListener对象
wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
// 对Consumer进行连接
status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
if (err != NO_ERROR) {
CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
strerror(-err), err);
} else {
mConsumer->setConsumerName(mName);
}
}
在以上方法中,会同时完成Consumer和BBQ的连接:
// frameworks/native/libs/gui/BufferQueueConsumer.cpp
status_t BufferQueueConsumer::connect(
const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
......
// ConsumerListener对象
mCore->mConsumerListener = consumerListener;
// Consumer是否由应用端控制
mCore->mConsumerControlledByApp = controlledByApp;
return NO_ERROR;
}
3.2、Surface和BBQ的连接过程
完成BBQ的创建后,BBQ需要通过IGraphicBufferProducer与实际的图形生产者进行连接后,才能接收来自生产者的Graphic Buffer。
连接时需要指定负责生产和提供图形数据的具体图形流生产者(即Producer API)。Android图形系统中,规定了四类Producer API:
// frameworks/native/libs/nativewindow/include/system/window.h
enum {
// 生产者为渲染引擎,如opengl、Vulkan,通过渲染引擎对Buffer入队
NATIVE_WINDOW_API_EGL = 1,
// 生产者为CPU,即软件绘制,绘制完成后直接入队
NATIVE_WINDOW_API_CPU = 2,
// 生产者为视频解码器,通过Stagefright操作对Buffer入队
NATIVE_WINDOW_API_MEDIA = 3,
// 生产者为Camera预览,通过Camera HAL对Buffer入队
NATIVE_WINDOW_API_CAMERA = 4,
};
Surface在图形渲染中作为生产者和消费者交换Buffer的接口,会在适当的流程中执行IGBP接口与BBQ的连接。
如果启用了硬件加速绘制,会在CanvasContext中通过CanvasContext::setupPipelineSurface()方法设置RenderPipeline时,会设置Producer API并回调Surface::connect()方法,和BBQ完成连接:
// frameworks/native/libs/gui/Surface.cpp
int Surface::connect(
int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
......
// 跟BBQ连接图形生产者
int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
......
return err;
}
如果是软件绘制,会在Surface::lock()时和BBQ进行连接:
// frameworks/native/libs/gui/Surface.cpp
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
......
if (!mConnectedToCpu) {
// Producer和BBQ进行连接
int err = Surface::connect(NATIVE_WINDOW_API_CPU);
if (err) {
return err;
}
......
}
进入BufferQueueProducer中的流程如下:
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput *output) {
......
int status = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
case NATIVE_WINDOW_API_CPU:
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
mCore->mConnectedApi = api;
......
if (listener != nullptr) {
// 设置Binder died监听
if (IInterface::asBinder(listener)->remoteBinder() != nullptr) {
status = IInterface::asBinder(listener)->linkToDeath(
static_cast<IBinder::DeathRecipient*>(this));
mCore->mLinkedToDeath = listener;
}
}
break;
default:
status = BAD_VALUE;
break;
}
......
return status;
}
在BufferQueueProducer::connect()方法中,除了指定Producer API之外,还传入了IProducerListener接口对象,作为BBQ中用于监听Surface所在进程死亡状态的接口使用。
需要注意的是,一个Surface只能和一个BBQ连接,一个BBQ也只能和一个Surface连接,否则就会出现如下异常:
E BufferQueueProducer: bbq-adapter#975(BLAST Consumer)975(id:13f400000552,api:1,p:5108,c:5108) connect: already connected (cur=1 req=1)
E libEGL : eglCreateWindowSurface: native_window_api_connect (win=0xb400007318a49010) failed (0xffffffea) (already connected to another API?)
3.3、生产和消费Graphic Buffer
当Surface和BBQ完成连接后,便可进行Graphic Buffer的传递。
- 获取Graphic Buffer:当需要渲染新的图像时,调用
IGBP::dequeueBuffer()方法,从BBQ返回一个可用的Graphic Buffer; - 填充Graphic Buffer:一旦获取到缓冲区,通过OpenGL ES进行渲染,将图像数据写入该缓冲区;
- 交换Graphic Buffer:渲染完成后,调用
IGBP::queueBuffer()方法,将填充完的缓冲区提交到BBQ中。
软件绘制时这个过程如下:
// frameworks/base/core/java/android/view/ViewRootImpl.java
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
// Draw with software renderer.
final Canvas canvas;
try {
// 获取Graphc Buffer:直接调用dequeueBuffer()
canvas = mSurface.lockCanvas(dirty);
}
try {
// 填充Graphc Buffer: 执行各种绘制
if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
}
canvas.translate(-xoff, -yoff);
canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
mView.draw(canvas);
} finally {
try {
// 交换Graphc Buffer: 直接调用queueBuffer()
surface.unlockCanvasAndPost(canvas);
} catch (IllegalArgumentException e) {
return false;
}
}
return true;
}
硬件加锁渲染时,通过绘制引擎管道进行dequeueBuffer和queueBuffer:
// frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
void CanvasContext::draw(bool solelyTextureViewUpdates) {
// 获取Graphic Buffer
Frame frame = getFrame();
......
IRenderPipeline::DrawResult drawResult;
{
// 填充Graphic Buffer:进行绘制
std::scoped_lock lock(mFrameMetricsReporterMutex);
drawResult = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry,
&mLayerUpdateQueue, mContentDrawBounds, mOpaque,
mLightInfo, mRenderNodes, &(profiler()), mBufferParams);
}
// 交换Graphic Buffer: 通过eglSwapBuffer/VulkanManager执行queueBuffer
bool didSwap = mRenderPipeline->swapBuffers(frame, drawResult, windowDirty, mCurrentFrameInfo,
&requireSwap);
mIsDirty = false;
.......
return;
}
执行完毕queueBuffer后,接下来会通过BufferQueueConsumer::acquireBuffer()将Graphic Buffer从队列中取出,并通过Transaction提交给surfaceflinger:
// frameworks/native/libs/gui/BLASTBufferQueue.cpp
status_t BLASTBufferQueue::acquireNextBufferLocked(
const std::optional<SurfaceComposerClient::Transaction*> transaction) {
......
BufferItem bufferItem;
// 从队列中获取Graphic Buffer
status_t status =
mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
......
// 将Buffer设置给Transaction
t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, mProducerId,
releaseBufferCallback);
// 提交Transaction
if (applyTransaction) {
t->setApplyToken(mApplyToken).apply(false, true);
}
......
return OK;
}
3.4、销毁BBQ
当BBQ不再使用时,需要主动进行销毁,避免出现内存泄漏。
Java层中,通过BLASTBufferQueue.destory()方法销毁BBQ:
// frameworks/base/graphics/java/android/graphics/BLASTBufferQueue.java
public void destroy() {
nativeDestroy(mNativeObject);
mNativeObject = 0;
}
并在完成BLASTBuffeQueue对象的析构后,陆续完成其他组件对象的析构。
四、BBQ模式设置
4.1、阻塞模式VS非阻塞模式
mCore->mDequeueBufferCannotBlock表示BBQ的阻塞模式或非阻塞模式。
该模式决定了BufferQueueProduer::dequeueBuffer操作未能获取到空闲Buffer时,是否需要阻塞等待,直到获得空闲Buffer。
默认为阻塞模式,只有同时满足以下三个条件时,此BBQ队列将为非阻塞模式:
mCore->mConsumerControlledByApp为true;BufferQueueProducer::mProducerControlledByApp为true;mDequeueTimeout< 0,即未指定dequeueBuffer超时时长。
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput *output) {
......
mCore->mDequeueBufferCannotBlock = false;
mCore->mQueueBufferCanDrop = false;
// 设置BBQ是否为非阻塞模式
if (mCore->mConsumerControlledByApp && producerControlledByApp) {
mCore->mDequeueBufferCannotBlock = mDequeueTimeout < 0;
mCore->mQueueBufferCanDrop = mDequeueTimeout <= 0;
}
return status;
}
mCore->mConsumerControlledByApp和producerControlledByApp表示BBQ中的Producer和Consumer行为是否由业务侧进行控制,从BBQ内部来看,其实就涉及到了两种模式。
4.2、丢弃模式
丢弃模式针对于某一个单一BufferItem对象,或者说是针对单个GraphicBuffer的属性,由BufferItem->mIsDroppable表示,在BufferQueueProducer::queueBuffer时设置:
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
.....
{ // Autolock scope
std::lock_guard<std::mutex> lock(mCore->mMutex);
// 设置是否可丢弃
item.mIsDroppable = mCore->mAsyncMode ||
(mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) ||
(mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||
(mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
if (mCore->mQueue.empty()) {
......
} else {
// When the queue is not empty, we need to look at the last buffer
// in the queue to see if we need to replace it
const BufferItem& last = mCore->mQueue.itemAt(
mCore->mQueue.size() - 1);
if (last.mIsDroppable) {
if (!last.mIsStale) {
// 丢弃上一个未出队的BufferItem
}
}
......
return NO_ERROR;
}
根据以上代码可知,满足以下任一条件mIsDroppable即可为true:
mCore->mAsyncMode为true,即当前BBQ为异步模式;mCore->mQueueBufferCanDrop为true;mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot:SharedBufferMode模式开启时,且恰好是SharedBufferSlot时。
mConsumerIsSurfaceFlinger是旧BufferQueue方案遗留的属性,BLAST方案中已全部弃用,恒为false;
mCore->mLegacyBufferDrop默认为true;
而mCore->mQueueBufferCanDrop值的设置也跟类似,必须同时满足以下条件:
-
mCore->mConsumerControlledByApp为true; -
BufferQueueProducer::mProducerControlledByApp为true; -
mDequeueTimeout<= 0,即未指定dequeueBuffer超时时长或指定时长为0。
当有新的BufferItem入队时,如果存在还未出队的BufferItem且是可丢弃的,则会直接丢弃:
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
.....
{ // Autolock scope
......
if (mCore->mQueue.empty()) {
.....
} else {
const BufferItem& last = mCore->mQueue.itemAt(
mCore->mQueue.size() - 1);
if (last.mIsDroppable) {
// 丢弃上一个未出队的BufferItem
if (!last.mIsStale) {
mSlots[last.mSlot].mBufferState.freeQueued();
if (!mSlots[last.mSlot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(last.mSlot);
mCore->mFreeBuffers.push_back(last.mSlot);
output->bufferReplaced = true;
}
}
// 用item替换last
mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
frameReplacedListener = mCore->mConsumerListener;
} else {
}
}
}
{ // scope for the lock
if (frameAvailableListener != nullptr) {
frameAvailableListener->onFrameAvailable(item);
} else if (frameReplacedListener != nullptr) {
frameReplacedListener->onFrameReplaced(item);
}
}
......
return NO_ERROR;
}
4.3、异步模式(Async Mode)
mCore->mAsyncMode表示BBQ的异步模式是否开启。
该值通过BufferQueueProducer::setAsyncMode()方法设置。
默认为同步模式,当异步模式开启后:
- Consumer最大
ACQUIREDBuffer数+1; queueBuffer时所有Buffer变为可丢弃模式;dequeuBuffer时变为非阻塞模式。
所有的虚拟屏关联Surface均为Async,目的是不阻塞sf。
4.4、共享Buffer模式(Shared Buffer Mode)
mCore->mSharedBufferMode表示BBQ的共享Buffer模式是否开启,较早版本或称为Single Buffer模式;
该值通过BufferQueueProducer::setSharedBufferMode()方法设置:
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::setSharedBufferMode(bool sharedBufferMode) {
std::lock_guard<std::mutex> lock(mCore->mMutex);
if (!sharedBufferMode) {
mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
}
mCore->mSharedBufferMode = sharedBufferMode;
return NO_ERROR;
}
当开启SharedBufferMode后,dequeueBuffer时第一次被获得的BufferSlot会被标记为共享Buffer,将mCore->mSlot的索引指赋值给mCore->mSharedBufferSlot,并在此后一直使用该Buffer。
mCore->mSharedBufferSlot代表共享Buffer的索引,在dequeueBuffer和queueBuffer时设置:
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
......
// 当SharedBufferMode开启后,第一次进行dequeue/queue的Buffer作为sharedBuffer
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
BufferQueueCore::INVALID_BUFFER_SLOT) {
mCore->mSharedBufferSlot = slot;
mSlots[slot].mBufferState.mShared = true;
}
......
}
SharedBufferMode开启后,后续的dequeueBuffer、queueBuffer將仅使用标记的Buffer进行,如在dequeueBuffer时,恒返回mCore->mSharedBufferSlot:
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
std::unique_lock<std::mutex>& lock, int* found) const {
while (tryAgain) {
if (tooManyBuffers) {
......
} else {
// 开启Shared buffer mode时,恒返回mCore->mSharedBufferSlot
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = mCore->mSharedBufferSlot;
} else {
......
}
}
}
}