SurfaceFlinger BlastBufferQueue生产者消费者模型
简述
BlastBufferQueue是一个消费者生产者的模型,他们消费生产的对象是GraphicBuffer,GraphicBuffer其实就是一块内存,只不过是一块比较特殊的内存,使用的是dma buffer,相比于一般的内存,它是一块更高效的跨进程共享内存,后面会专门有一篇来介绍它。
在Android 12开始,无论是这个模型的消费者还是生产者都在app侧,应用在渲染前,去队列里拿一块buffer,然后进行渲染,后放回队列,并且通知消费者可以取buffer消费,就是让SurfaceFlinger用于合成。
在开始介绍BlastBufferQueue之前,我们还有要介绍一下fence,栅栏。大家在多线程编程中都接触过锁吧,用来保证多线程读写数据时候的线程安全,fence其实也是类似,只不过fence可以跨越进程和硬件设备。(在我们现在这个场景设备说的是cpu,gpu,hwc)
Fence 栅栏
我们上一片详细说过fence的,这里只再简单复述一下他的作用,因为在这篇文章中会经常看到。
fence的作用和多线程中的锁类似,只不过他是跨进程,跨硬件的。我们这里生产者需要gpu来渲染,消费者拿到buffer可能需要hwc来合成,所以需要跨设备。
举个我们本节内容的具体的例子:
我们Surface.lock后会获取一个buffer,然后要通过cpu执行一些opengel指令告诉gpu怎么渲染,cpu执行完后,gpu不可能立刻完成渲染。这时候cpu有两种方案,一个是等gpu执行完,然后再把这个buffer给出去,但是这样会浪费这个cpu的资源;第二种方案,就是通过fence,cpu可以继续执行其他任务,到需要使用这个buffer的时候,再通过fence来确认gpu任务是否完成。
BlastBufferQueue构建
1.1 updateBlastSurfaceIfNeeded()
我们在SurfaceFlinger和端侧的Binder框架文章的末尾提到了WMS将构建好的SurfaceContorl传回app后,app会构建BlastBufferQueue。
void updateBlastSurfaceIfNeeded() {
if (!mSurfaceControl.isValid()) {
return;
}
if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
mBlastBufferQueue.update(mSurfaceControl,
mSurfaceSize.x, mSurfaceSize.y,
mWindowAttributes.format);
return;
}
if (mBlastBufferQueue != null) {
mBlastBufferQueue.destroy();
}
// 首次走这里,构建消费者生产者队列模型。详见1.2
mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
// 构建Sufrace。
Surface blastSurface = mBlastBufferQueue.createSurface();
mSurface.transferFrom(blastSurface);
}
1.2 BLASTBufferQueue构造函数
调用了nativeCreate构造c++层的BlastBufferQueue,并且返回c++侧这个对象的内存地址,记录到mNativeObject进行关联。
调用nativeUpdate更新参数。它不仅会修改app层buffer的参数,还会通知到SurfaceFlinger。
这个模式和上一篇文章介绍的SurfaceControl类似,java层和c++层各有一个对象相互关联起来,这个用法非常常见。
public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
@PixelFormat.Format int format) {
// 调用重载的构造方法,后面会调用nativeCreate
this(name, true /* updateDestinationFrame */);
// 更新参数,实际会调用到native方法
update(sc, width, height, format);
}
public BLASTBufferQueue(String name, boolean updateDestinationFrame) {
// 调用nativeCreate构造c++侧的BLASTBufferQueue,返回一个地址
// 详见1.3
mNativeObject = nativeCreate(name, updateDestinationFrame);
}
public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format) {
nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format);
}
1.3 BLASTBufferQueue::nativeCreate
构造BLASTBufferQueue
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName,
jboolean updateDestinationFrame) {
ScopedUtfChars name(env, jName);
// 构造c++的BLASTBufferQueue,详见1.4
sp<BLASTBufferQueue> queue = new BLASTBufferQueue(name.c_str(), updateDestinationFrame);
queue->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(queue.get());
}
1.4 BLASTBufferQueue构造函数(c++侧)
初始化一些变量
调用了createBufferQueue创建生产者和消费者
createBufferQueue里面构造的消费者是BufferQueueConsumer,然后这里通过它构造BLASTBufferItemConsumer。
同时还配置了消费者和生产者的一些参数,超时以及存取最大Buffer。
调用setFrameAvailableListener注册了回调。
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame)
: mSurfaceControl(nullptr),
mSize(1, 1),
mRequestedSize(mSize),
mFormat(PIXEL_FORMAT_RGBA_8888),
mTransactionReadyCallback(nullptr),
mSyncTransaction(nullptr),
mUpdateDestinationFrame(updateDestinationFrame) {
// 构造队列,详见1.5
createBufferQueue(&mProducer, &mConsumer);
mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());
mProducer->setMaxDequeuedBufferCount(2);
// mConsumer指向createBufferQueue里面构造的BufferQueueConsumer
// BLASTBufferItemConsumer这里就是包装了一下BufferQueueConsumer,详见1.8
mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
GraphicBuffer::USAGE_HW_COMPOSER |
GraphicBuffer::USAGE_HW_TEXTURE,
1, false, this);
static std::atomic<uint32_t> nextId = 0;
mProducerId = nextId++;
// 这里注册了listener回调,this就是BLASTBufferQueue,细节1.9会介绍
mBufferItemConsumer->setFrameAvailableListener(this);
ComposerServiceAIDL::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
mNumAcquired = 0;
mNumFrameAvailable = 0;
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);
BQA_LOGV("BLASTBufferQueue created");
}
1.5 createBufferQueue
void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer) {
// 。。。
// 构造队列,详见1.5.1
sp<BufferQueueCore> core(new BufferQueueCore());
// 。。。
// 构造生产者,详见 1.6
sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core, this));
// 构造消费者,详见 1.7
sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
consumer->setAllowExtraAcquire(true);
*outProducer = producer;
*outConsumer = consumer;
}
1.5.1 BufferQueueCore构造函数
BufferQueueCore是这个消费者生产者模型记录数据的类,可以看到这里初始化了大量的变量。我们来介绍一些比较核心的变量。
- mSlots,SlotsType类型
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS]
NUM_BUFFER_SLOTS是64,mSlots就是一个BufferSlot的数组,BufferSlot里面有一个GraphicBuffer的指针,记录了关联的buffer,还有一个Fence指针和EGLSyncKHR,分别用于渲染和合成的同步。
Slots可以理解为一个缓存池,避免重复构造释放对象。 - mQueue,Fifo类型
typedef Vector Fifo
这个是消费者生产者队列,BufferItem里面有一个对应mSlot的索引,还有一个Fence指针,一个GraphicBuffer指针。 - mFreeSlots set
mSlots空闲的索引。这里的空闲是指没有关联buffer,即GraphicBuffer的指针为空 - mFreeBuffer list
mSlot空闲的索引。这些BufferSlot是已经关联GraphicBuffer的。 - mUnusedSlots list
从未使用过的mSlot索引,前面我们说过mSlot是大小为64的数组,但是一般并不会64个都用到,BufferQueueCore有一个变量mMaxBufferCount来决定会有多少个Slot会被用到。 - mActiveBuffers std::set
包含所有non-free状态buffer的Slot,DEQUEUED,QUEUED,ACQUIRED以及SHARED - mAllowAllocation bool
决定dequeueBuffer过程中是否允许去分配GraphicBuffer
这里Slot有5种状态,DEQUEUED,QUEUED,ACQUIRED,FREE,SHARED
这几种状态逻辑很简单
生产者调用dequeueBuffer获取slot后就进入DEQUEUED状态
生产者使用完buffer调用queueBuffer后把buffer放到列表里就进入了QUEUED状态
消费者使用acquireBuffer获取Buffer后buffer就进入ACQUIRED状态
消费者使用releaseBuffer把Buffer释放后,就进入FREE状态
SHARED状态比较特殊,这里有一个共享Buffer模式,看代码实现逻辑就是一直共享复用一个buffer,这种情况这个buffer就是SHARED状态,默认情况是不使用这种模式的,我们不会太关注这个。
其实光看这些变量我们就大概能猜到这个BlastBufferQueue大体是怎么运作的了。
BufferQueueCore::BufferQueueCore()
: mMutex(),
mIsAbandoned(false),
mConsumerControlledByApp(false),
mConsumerName(getUniqueName()),
mConsumerListener(),
mConsumerUsageBits(0),
mConsumerIsProtected(false),
mConnectedApi(NO_CONNECTED_API),
mLinkedToDeath(),
mConnectedProducerListener(),
mBufferReleasedCbEnabled(false),
mSlots(),
mQueue(),
mFreeSlots(),
mFreeBuffers(),
mUnusedSlots(),
mActiveBuffers(),
mDequeueCondition(),
mDequeueBufferCannotBlock(false),
mQueueBufferCanDrop(false),
mLegacyBufferDrop(true),
mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
mDefaultWidth(1),
mDefaultHeight(1),
mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
mMaxAcquiredBufferCount(1),
mMaxDequeuedBufferCount(1),
mBufferHasBeenQueued(false),
mFrameCounter(0),
mTransformHint(0),
mIsAllocating(false),
mIsAllocatingCondition(),
mAllowAllocation(true),
mBufferAge(0),
mGenerationNumber(0),
mAsyncMode(false),
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) {
int numStartingBuffers = getMaxBufferCountLocked();
for (int s = 0; s < numStartingBuffers; s++) {
mFreeSlots.insert(s);
}
for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
s++) {
mUnusedSlots.push_front(s);
}
}
1.6 BBQBufferQueueProducer继承BufferQueueProducer
BBQBufferQueueProducer把BLASTBufferQueue存在了变量里,然后调用父类的构造函数。
BufferQueueProducer构造函数初始化了一些变量,主要注意的是mCore和mSlots,存了前面构造的BufferQueueCore以及mSlots
BBQBufferQueueProducer(const sp<BufferQueueCore>& core, wp<BLASTBufferQueue> bbq)
: BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/),
mBLASTBufferQueue(std::move(bbq)) {}
BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
bool consumerIsSurfaceFlinger) :
mCore(core),
mSlots(core->mSlots),
mConsumerName(),
mStickyTransform(0),
mConsumerIsSurfaceFlinger(consumerIsSurfaceFlinger),
mLastQueueBufferFence(Fence::NO_FENCE),
mLastQueuedTransform(0),
mCallbackMutex(),
mNextCallbackTicket(0),
mCurrentCallbackTicket(0),
mCallbackCondition(),
mDequeueTimeout(-1),
mDequeueWaitingForAllocation(false) {}
1.7 BufferQueueConsumer构造函数也很简单,主要也是存了一下BufferQueueCore以及mSlots
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
mCore(core),
mSlots(core->mSlots),
mConsumerName() {}
1.8 BLASTBufferItemConsumer构造函数
这里主要有consumerlistener的注册,生产者queueBuffer后就会通过这个监听器来通知消费者。
继承BLASTBufferItemConsumer,会调用BufferItemConsumer的构造函数。
BufferItemConsumer继承了ConsumerBase,在ConsumerBase构造函数中调用consumerConnect进行监听器注册。
BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
int bufferCount, bool controlledByApp)
: BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
mCurrentlyConnected(false),
mPreviouslyConnected(false) {}
BufferItemConsumer::BufferItemConsumer(
const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
int bufferCount, bool controlledByApp) :
ConsumerBase(consumer, controlledByApp)
{
status_t err = mConsumer->setConsumerUsageBits(consumerUsage);
LOG_ALWAYS_FATAL_IF(err != OK,
"Failed to set consumer usage bits to %#" PRIx64, consumerUsage);
if (bufferCount != DEFAULT_MAX_BUFFERS) {
err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
LOG_ALWAYS_FATAL_IF(err != OK,
"Failed to set max acquired buffer count to %d", bufferCount);
}
}
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
mAbandoned(false),
mConsumer(bufferQueue),
mPrevFinalReleaseFence(Fence::NO_FENCE) {
// Choose a name using the PID and a process-unique ID.
mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
// 这里的this是ConsumerBase,Consumer的回调只是做一层中转,详见1.9
wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
// 注册ConsumerListener
status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
// 。。。
}
1.9 ConsumerBase::onFrameAvailable
onFrameAvailable是ConsumerListener接口的方法之一,我们就用它举例,其他的也是一样的逻辑
前面说过这里只是一层中转,最终调用的是mFrameAvailableListener变量的回调方法。
这里mFrameAvailableListener是在1.4注册的,就是BLASTBufferQueue。
后面的逻辑是消费者相关的逻辑,我们在3.1再介绍。
void ConsumerBase::onFrameAvailable(const BufferItem& item) {
CB_LOGV("onFrameAvailable");
sp<FrameAvailableListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mFrameAvailableMutex);
listener = mFrameAvailableListener.promote();
}
if (listener != nullptr) {
CB_LOGV("actually calling onFrameAvailable");
listener->onFrameAvailable(item);
}
}
队列的生产端
我们从ViewRootImpl里面的drawSoftware开始分析数据的生产者,至于什么时候会走到这里,我们会在讲Vsync的篇章里面介绍。
做过app开发一定知道,写自定义view的时候我们会复写onDraw去实现想要的效果,而onDraw就是在这里调用的。
现在版本的android基本已经不用软件渲染了,都是硬件渲染,但是我们还是都介绍了一下他们的流程,不关心的软件渲染的可以直接跳到硬件渲染
软件渲染
如果是软件绘制的话,我们就需要通过lockCanvas去取一块图元buffer,draw结束后通过unlockCanvasAndPost把buffer放回队列,供消费者使用。
2.1.1 ViewRootImpl.drawSoftware
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
// 。。。
// 获取图元buffer,dequeueBuffer流程,详见2.1.2
canvas = mSurface.lockCanvas(dirty);
// 。。。
mView.draw(canvas);
// 。。。
surface.unlockCanvasAndPost(canvas);
}
2.1.2 Surface.lockCanvas
调用nativeLockCanvas
public Canvas lockCanvas(Rect inOutDirty)
throws Surface.OutOfResourcesException, IllegalArgumentException {
synchronized (mLock) {
// 。。。判断是否重复锁
// 调用nativeLockCanvas,详见2.1.3
mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
return mCanvas;
}
}
2.1.3 Surface::nativeLockCanvas
校验Surface,设置纹理格式
调用surface::lock进一步dequeueBuffer
配置canvas返回给java层绘制使用
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
// 。。。Surface有效性校验,设置纹理格式
Rect dirtyRect(Rect::EMPTY_RECT);
Rect* dirtyRectPtr = NULL;
// 获取参数里传入的脏区数据
if (dirtyRectObj) {
dirtyRect.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
dirtyRect.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
dirtyRect.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
dirtyRectPtr = &dirtyRect;
}
ANativeWindow_Buffer buffer;
// 这里去队列中取buffer,会存到buffer里,详见2.1.4
status_t err = surface->lock(&buffer, dirtyRectPtr);
// 。。。 返回值检测,如果有异常则抛出一个java异常
// 把canvas和获取的Buffer关联。
graphics::Canvas canvas(env, canvasObj);
canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));
if (dirtyRectPtr) {
canvas.clipRect({dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom});
}
if (dirtyRectObj) {
env->SetIntField(dirtyRectObj, gRectClassInfo.left, dirtyRect.left);
env->SetIntField(dirtyRectObj, gRectClassInfo.top, dirtyRect.top);
env->SetIntField(dirtyRectObj, gRectClassInfo.right, dirtyRect.right);
env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
}
sp<Surface> lockedSurface(surface);
lockedSurface->incStrong(&sRefBaseOwner);
return (jlong) lockedSurface.get();
}
2.1.4 Surface::lock
调用connect进行一些初始化逻辑
调用BufferQueueProducer.dequeueBuffer,核心逻辑,获取slot和buffer。
计算需要重新绘制渲染的区域。
调用backBuffer->lockAsync锁定buffer,和后面unlock相对称,主要做的事是将底层分配的buffer做一个map,映射到进程空间,在执行映射前会等fence完成,确保buffer其他人使用完成了.
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
// 。。。检测是否已经lock了(mLockBuffer不为空)
if (!mConnectedToCpu) {
// 调用connect,详见2.1.5
int err = Surface::connect(NATIVE_WINDOW_API_CPU);
if (err) {
return err;
}
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
}
ANativeWindowBuffer* out;
int fenceFd = -1;
// 调用dequeueBuffer 详见2.1.7
status_t err = dequeueBuffer(&out, &fenceFd);
if (err == NO_ERROR) {
// 获取新分配的buffer
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
const Rect bounds(backBuffer->width, backBuffer->height);
// 根据入参,脏区和新建的buffer做位运算,计算出脏数据区域。如果入参为空,则新的整个buffer都是脏区域
Region newDirtyRegion;
if (inOutDirtyBounds) {
newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
newDirtyRegion.andSelf(bounds);
} else {
newDirtyRegion.set(bounds);
}
// mPostedBuffer是上次提交的Buffer,这里类似双缓存buffer的概念,
// mPostedBuffer为目前前台显示buffer,新dequeue的是后台在渲染的buffer
// 这里比较buffer宽高和编码模式是否变化,没有变化才可以把前台buffer数据拷贝过来,再结合newDirtyRegion减少需要渲染的范围。
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
const bool canCopyBack = (frontBuffer != nullptr &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format);
if (canCopyBack) {
// 拷贝前台区域,减少需要重新渲染的区域。
const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty()) {
copyBlt(backBuffer, frontBuffer, copyback, &fenceFd);
}
} else {
// 如果不能拷贝前台buffer,整个区域都是需要重新渲染的
newDirtyRegion.set(bounds);
mDirtyRegion.clear();
Mutex::Autolock lock(mMutex);
for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
mSlots[i].dirtyRegion.clear();
}
}
{ // scope for the lock
Mutex::Autolock lock(mMutex);
// 根据buffer获取slot索引
int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
if (backBufferSlot >= 0) {
Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
mDirtyRegion.subtract(dirtyRegion);
dirtyRegion = newDirtyRegion;
}
}
mDirtyRegion.orSelf(newDirtyRegion);
// 最终计算的区域通过参数返回。
if (inOutDirtyBounds) {
*inOutDirtyBounds = newDirtyRegion.getBounds();
}
void* vaddr;
// 锁定buffer,传入了fence,这里的逻辑我们也暂时不看,等GraphicBuffer章节再介绍
status_t res = backBuffer->lockAsync(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr, fenceFd);
if (res != 0) {
err = INVALID_OPERATION;
} else {
mLockedBuffer = backBuffer;
outBuffer->width = backBuffer->width;
outBuffer->height = backBuffer->height;
outBuffer->stride = backBuffer->stride;
outBuffer->format = backBuffer->format;
outBuffer->bits = vaddr;
}
}
return err;
}
2.1.5 Surface::connect
经过一系列重载会调用到这个函数
int Surface::connect(
int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
// 。。。
IGraphicBufferProducer::QueueBufferOutput output;
mReportRemovedBuffers = reportBufferRemoval;
// 调用生产者的connect,详见2.1.6
int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
// 从BufferQueueCore拿到存在output里面的一些变量记录到Surface里,比如宽高。
if (!err && api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = true;
// Clear the dirty region in case we're switching from a non-CPU API
mDirtyRegion.clear();
} else if (!err) {
mDirtyRegion = Region::INVALID_REGION;
}
return err;
}
2.1.6 BBQBufferQueueProducer::connect
主要调用的是父类的connect,我们这里直接看父类BufferQueueProducer::connect
重新计算最大buffer数,调整mSlot的几个队列。(比如如果最大buffer数扩大了,就要从unUsedSlots里移动对应数量到mFreeSlots)
计算最大Buffer到数量逻辑为mMaxAcquiredBufferCount+mMaxDequeuedBufferCount+(如果是异步模式还要加一个),这里计算出来的和配置的mMaxBufferCount更小的一个值就是最终最大buffer个数。
如果传入listener不为空就存储到变量里。
status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput *output) {
// 参数有效性校验
// 重新计算最大buffer数,更新调整mSlot
int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
mDequeueTimeout < 0 ?
mCore->mConsumerControlledByApp && producerControlledByApp : false,
mCore->mMaxBufferCount) -
mCore->getMaxBufferCountLocked();
if (!mCore->adjustAvailableSlotsLocked(delta)) {
BQ_LOGE("connect: BufferQueue failed to adjust the number of available "
"slots. Delta = %d", delta);
return BAD_VALUE;
}
mCore->mConnectedApi = api;
// 把BufferQueueCore里面的参数取出来填充至output
// 。。。
if (listener != nullptr) {
// 。。。如果参数listener不为空,这里记录一下listener
mCore->mConnectedProducerListener = listener;
mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify();
}
//。。。配置BufferQueueCore的一些变量
VALIDATE_CONSISTENCY();
return status;
}
2.1.7 Surface::dequeueBuffer
这里有一个共享buffer模式,默认情况不用使用这种模式,从逻辑上看就是复用同一个buffer,索引存在mSharedBufferSlot。
这里核心就是通过调用mGraphicBufferProducer->dequeueBuffer从mSlots里获取一个空闲的Slot,把它变成DEQUEUE状态,用来绘制。
如果Slot里面的buffer不符合我们的条件,需要重新分配,例如Surface大小变化了,或者format变化了,所需要buffer大小不同了,那么就需要调用mGraphicBufferProducer->requestBuffer重新分配GraphicBuffer了,这个流程我们放到GraphicBuffer流程介绍。
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
IGraphicBufferProducer::DequeueBufferInput dqInput;
{
Mutex::Autolock lock(mMutex);
if (mReportRemovedBuffers) {
mRemovedBuffers.clear();
}
// 从Surface里获取一些参数封装到DequeueBufferInput
// 主要是宽高和format(format是图像编码格式)
getDequeueBufferInputLocked(&dqInput);
// 如果是共享buffer模式,并且已经分配了共享buffer,直接返回。
if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot !=
BufferItem::INVALID_BUFFER_SLOT) {
sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
if (gbuf != nullptr) {
*buffer = gbuf.get();
*fenceFd = -1;
return OK;
}
}
}
int buf = -1;
sp<Fence> fence;
nsecs_t startTime = systemTime();
FrameEventHistoryDelta frameTimestamps;
// 调用生产者dequeueBuffer 详见2.6
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width,
dqInput.height, dqInput.format,
dqInput.usage, &mBufferAge,
dqInput.getTimestamps ?
&frameTimestamps : nullptr);
//。。。
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
freeAllBuffers();
}
// 我们之前是从mSlots列表里拿了一个索引,对应分配了一个Slot
// 这里根据返回值确认是否需要重新分配Slot里面的GraphicBuffer(比如画面大小变化了,需要的buffer大小不一样了,就需要重新分配buffer)
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
if (mReportRemovedBuffers && (gbuf != nullptr)) {
mRemovedBuffers.push_back(gbuf);
}
// 这个方法是分配GraphicBuffer的,这个流程我们放到GraphicBuffer到部分介绍。
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
// 。。。
}
if (fence->isValid()) {
// fence之前提过它的作用,
*fenceFd = fence->dup();
} else {
*fenceFd = -1;
}
*buffer = gbuf.get();
// 如果是共享buffer模式,需要把分配到的buffer索引存到mSharedBufferSlot
if (mSharedBufferMode && mAutoRefresh) {
mSharedBufferSlot = buf;
mSharedBufferHasBeenQueued = false;
} else if (mSharedBufferSlot == buf) {
mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
mSharedBufferHasBeenQueued = false;
}
// 记录dequeue的slot索引
mDequeuedSlots.insert(buf);
return OK;
}
硬件渲染
ViewRootImpl的performTraversals流程中draw时候,如果是软件渲染会调用上面提到的drawSoftware,而如果是硬件渲染就是调用ThreadedRender的draw
这里省略了许多代码,包括怎么将上层canvas的操作接口转换成最终的gpu指令,这里我们重点关注dequeueBuffer流程,就省略其他的步骤了。
2.2 ThreadedRender::draw
我们主要关注dequeueBuffer的流程,就省略掉了其他的流程(包括把canvas的指令做转换存储等)
void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
// 。。。
// 调用了syncAndDrawFrame
int syncResult = syncAndDrawFrame(frameInfo);
// 。。。
}
2.3 HardwareRender::syncAndDrawFrame
ThreadedRender是HardwareRender的子类,所以这里调用了HardwareRender的syncAndDrawFrame,这是一个native方法,通过jni调用到c++层
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlongArray frameInfo,
jint frameInfoSize) {
LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
"Mismatched size expectations, given %d expected %zu", frameInfoSize,
UI_THREAD_FRAME_INFO_SIZE);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
return proxy->syncAndDrawFrame();
}
2.4 DrawFrameTask::syncFrameState
RenderProxy::syncAndDrawFrame->DrawFrameTask::drawFrame->DrawFrameTask::run->DrawFrameTask::syncFrameState
中间这些流程没有我们这里关心的内容就省略了。
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
// 。。。
// 这里的 mContext是一个CanvasContext,里面持有一个ReliableSurface
mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
// 。。。
}
CanvasContext::prepareTree
void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued,
RenderNode* target) {
// 。。。
// mNativeSurface是一个ReliableSurface,它绑定了一个ANativeWindow,ANativeWindow封装了底层的对Buffer的一些操作,后面dequeueBuffer也是通过它来调用的
int err = mNativeSurface->reserveNext();
// 。。。
}
2.5 int ReliableSurface::reserveNext
我们这里出现了几个和渲染相关的窗口类,ReliableSurface,Surface,ANativeWindow。
这几个类都是一一对应的。在第二节结尾,我们提到过创建layer流程最后会通过mBlastBufferQueue.createSurface构建一个Surface,这个Surface是java层的,native层对应了一个BBQSurface,继承了Native的Surface,而Native的Surface继承了ANativeWindow。
HardwareRenderer会通过setSurface让ReliableSurface关联上前面创建的Surface(也就是ANativeWindow子类)
ANativeWindow是底层去操作GraphicBuffer的类,而Surface和ReliableSurface都是对ANativeWindow的封装。
int ReliableSurface::reserveNext() {
if constexpr (DISABLE_BUFFER_PREFETCH) {
return OK;
}
//。。。
int fenceFd = -1;
// ANativeWindowBuffer继承GrapherBuffer,就是我们这里需要最终申请的Buffer的一个封装。
ANativeWindowBuffer* buffer = nullptr;
// 就是在这里调用dequeueBuffer
// mWindow是一个ANativeWindow,里面的函数指针会被绑定到真实的dequeueBuffer等操作上面。
int result = ANativeWindow_dequeueBuffer(mWindow, &buffer, &fenceFd);
{
std::lock_guard _lock{mMutex};
LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext");
mReservedBuffer = buffer;
mReservedFenceFd.reset(fenceFd);
}
return result;
}
dequeuBuffer流程
2.6 BufferQueueProducer::dequeueBuffer
这个方法比较长,但是做的事也不复杂,主要是一下几个:
参数校验,以及判断是不是没有可用buffer,并且正在分配,如果是则等待分配完成。然后检测一些必要入参是否为0,如果为0就使用BufferQueueCore中的默认参数。
接下去调用waitForFreeSlotThenRelock进行slot分配。
分配到slot后通过needsReallocation检测buffer是否需要以及可以重新分配。
如果需要重新分配则构建GraphicBuffer。关于GraphicBuffer我们会专门有一片文章来介绍。
回调mConsumerListener->onFrameDequeued,等待eglfence,这个eglfence是releaseBuffer时候配置的,等待gpu/hwc使用完成这个buffer。
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
// 。。。参数校验
status_t returnFlags = NO_ERROR;
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
bool attachedByConsumer = false;
{
std::unique_lock<std::mutex> lock(mCore->mMutex);
// 如果没有空闲Buffer了,并且正在dequeue。
if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
mDequeueWaitingForAllocation = true;
mCore->waitWhileAllocatingLocked(lock);
mDequeueWaitingForAllocation = false;、
mDequeueWaitingForAllocationCondition.notify_all();
}
// 入参没有配置format,使用BufferQueueCore默认format
if (format == 0) {
format = mCore->mDefaultBufferFormat;
}
usage |= mCore->mConsumerUsageBits;
// 如果入参没有宽高,则使用BufferQueueCore默认宽高
const bool useDefaultSize = !width && !height;
if (useDefaultSize) {
// 。。。
}
int found = BufferItem::INVALID_BUFFER_SLOT;
while (found == BufferItem::INVALID_BUFFER_SLOT) {
// 获取一个slot,详见2.7
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
// 。。。
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
// 如果不允许在dequeueBuffer过程中分配buffer,并且当前buffer需要重新分配,就放弃当前找到的slot,重新进入下一次循环通过waitForFreeSlotThenRelock找一个。
if (!mCore->mAllowAllocation) {
// needsReallocation用于判断buffer是否需要重新分配。详见2.8
if (buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
if (mCore->mSharedBufferSlot == found) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a sharedbuffer");
return BAD_VALUE;
}
mCore->mFreeSlots.insert(found);
mCore->clearBufferSlotLocked(found);
found = BufferItem::INVALID_BUFFER_SLOT;
continue;
}
}
}
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
// 判断是否需要重新分配buffer,共享buffer模式不允许重新分配。
if (mCore->mSharedBufferSlot == found &&
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
"buffer");
return BAD_VALUE;
}
// 共享模式如果这次找到的和之前不一样,把这次找到的slot放到mActiveBuffers
if (mCore->mSharedBufferSlot != found) {
mCore->mActiveBuffers.insert(found);
}
*outSlot = found;
ATRACE_BUFFER_INDEX(found);
attachedByConsumer = mSlots[found].mNeedsReallocation;
mSlots[found].mNeedsReallocation = false;
mSlots[found].mBufferState.dequeue();
if ((buffer == nullptr) ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
// 如果需要重新分配buffer,重置一些变量,返回值里标记BUFFER_NEEDS_REALLOCATION
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = nullptr;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->mBufferAge = 0;
mCore->mIsAllocating = true;
returnFlags |= BUFFER_NEEDS_REALLOCATION;
} else {
// 。。。
}
// 。。。
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
*outFence = (mCore->mSharedBufferMode &&
mCore->mSharedBufferSlot == found) ?
Fence::NO_FENCE : mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
if (!(returnFlags & BUFFER_NEEDS_REALLOCATION)) {
if (mCore->mConsumerListener != nullptr) {
// 如果不需要重新分配buffer,这里就可以回调mConsumerListener.onFrameDequeued,dequeueBuffer基本完成了。
mCore->mConsumerListener->onFrameDequeued(mSlots[*outSlot].mGraphicBuffer->getId());
}
}
} // Autolock scope
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
// 构建GrahpicBuffer,我们放到GraphicBuffer到篇章介绍
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
width, height, format, BQ_LAYER_COUNT, usage,
{mConsumerName.string(), mConsumerName.size()});
status_t error = graphicBuffer->initCheck();
// 。。。
// 回调mConsumerListener.onFrameDequeued
mCore->mConsumerListener->onFrameDequeued(mSlots[*outSlot].mGraphicBuffer->getId());
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.notify_all();
// 。。。
}
if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
// 这里点eglFence是releaseBuffer时传过来的,如果有就要等待,否则说明buffer还在被SurfaceFlinger合成使用。
if (eglFence != EGL_NO_SYNC_KHR) {
EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
1000000000);
// 。。。
}
// 。。。
return returnFlags;
}
2.7 BufferQueueProducer::waitForFreeSlotThenRelock
这个方法主要做了以下几件事:
统计一下dequeued buffer和queued buffer个数是否超过上限。如果超过上限则等待mDequeueCondition唤醒进入下一次循环。
如果是共享buffer模式,并且共享buffer slot已经分配了,则直接返回当前的共享buffer。
从mFreeBuffers或者mFreeSlots取一个空闲的slot,如果成功则返回,失败则等待mDequeueCondition唤醒进入下一次循环。
而queueBuffer,acquireBuffer,releaseBuffer等执行后可能释放出slot的操作都会触发mDequeueCondition.notifyAll。
status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
std::unique_lock<std::mutex>& lock, int* found) const {
auto callerString = (caller == FreeSlotCaller::Dequeue) ?
"dequeueBuffer" : "attachBuffer";
bool tryAgain = true;
while (tryAgain) {
int dequeuedCount = 0;
int acquiredCount = 0;
// 统计dequeued和queued状态的buffer个数
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isDequeued()) {
++dequeuedCount;
}
if (mSlots[s].mBufferState.isAcquired()) {
++acquiredCount;
}
}
// 如果DEQUEUED buffer已经到上限,就返回INVALID_OPERATION
if (mCore->mBufferHasBeenQueued &&
dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
// 。。。
return INVALID_OPERATION;
}
*found = BufferQueueCore::INVALID_BUFFER_SLOT;
// 检测当前队列是否已经满了,即QUEUED buffer是否到上限
const int maxBufferCount = mCore->getMaxBufferCountLocked();
bool tooManyBuffers = mCore->mQueue.size()
> static_cast<size_t>(maxBufferCount);
if (tooManyBuffers) {
// 如果QUEUED buffer上限了就打个日志,什么都不做在后面会挂起等待。
BQ_LOGV("%s: queue size is %zu, waiting", callerString,
mCore->mQueue.size());
} else {
// 共享buffer模式,并且已经分配了SHARED buffer,就直接把这个slot返回即可
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = mCore->mSharedBufferSlot;
} else {
// 这里分caller分Dequeue和Attach,区别就是优先使用getFreeBufferLocked还是getFreeSlotLocked分配slot。
// 这两个方法的区别是分别从mFreeBuffers和mFreeSlots里获取slot
// 这两个变量我们在1.5.1介绍过了,区别就是slot是否已经关联GraphicBuffer
// 从dequeueBuffer过来就是走上面的逻辑
if (caller == FreeSlotCaller::Dequeue) {
// 从FreeBuffers里获取空闲slot,详见2.7.1
int slot = getFreeBufferLocked();
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else if (mCore->mAllowAllocation) {
// 从FreeSlots里获取空闲slot,详见2.7.2
*found = getFreeSlotLocked();
}
} else {
// If we're calling this from attach, prefer free slots
int slot = getFreeSlotLocked();
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else {
*found = getFreeBufferLocked();
}
}
}
}
// 如果没有找到buffer,则tryAagain为true。
tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) ||
tooManyBuffers;
if (tryAgain) {
// 如果配置的是非阻塞的,则这里直接返回一个错误码
if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) &&
(acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
return WOULD_BLOCK;
}
// 否则检测一下是否已经超时了,超时了就返回一个错误码,否则就在mDequeueCondition上等待。
// queueBuffer,releaseBuffer等时机会触发mDequeueCondition.notifyAll()
if (mDequeueTimeout >= 0) {
std::cv_status result = mCore->mDequeueCondition.wait_for(lock,
std::chrono::nanoseconds(mDequeueTimeout));
if (result == std::cv_status::timeout) {
return TIMED_OUT;
}
} else {
mCore->mDequeueCondition.wait(lock);
}
}
} // while (tryAgain)
return NO_ERROR;
}
2.7.1 getFreeBufferLocked
有了上面的介绍这里其实不看代码大家也能猜到做了什么吧。就是从mFreeBuffers取一个slot索引。
int BufferQueueProducer::getFreeBufferLocked() const {
if (mCore->mFreeBuffers.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
int slot = mCore->mFreeBuffers.front();
mCore->mFreeBuffers.pop_front();
return slot;
}
2.7.2 getFreeSlotLocked
逻辑同上,只不过把mFreeBuffers换成mFreeSlots。
int BufferQueueProducer::getFreeSlotLocked() const {
if (mCore->mFreeSlots.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
int slot = *(mCore->mFreeSlots.begin());
mCore->mFreeSlots.erase(slot);
return slot;
}
2.8 needsReallocation
就是判断一些属性是否发生变化了,如宽,高,编码格式等,如果变化的则buffer大小就会变化,就需要重新分配。
bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage)
{
if (static_cast<int>(inWidth) != width) return true;
if (static_cast<int>(inHeight) != height) return true;
if (inFormat != format) return true;
if (inLayerCount != layerCount) return true;
if ((usage & inUsage) != inUsage) return true;
if ((usage & USAGE_PROTECTED) != (inUsage & USAGE_PROTECTED)) return true;
return false;
}
到这里dequeueBuffer的逻辑我们就介绍完了,其实总结一下核心逻辑就是去mFreeBuffers或者mFreeSlots里获取一个空闲slot,然后判断是否需要重新为这个slot分配一个GraphicBuffer。
queueBuffer流程
接下来我们来看下queueBuffer流程,我们上面拿到buffer后,就会调用view的draw方法会做绘制了,我们调用canvas方法绘制的时候其实还并没有真正往buffer上写数据,只是记录了一些指令,cpu后续向gpu发送绘制指令,只有到gpu完成渲染这个buffer才算是生产者用完了。
3.1 这里回调到queueBuffer流程和前面到dequeueBuffer流程类似,我们就不看了。
3.2 Surface::queueBuffer
主要是调用了mGraphicBufferProducer->queueBuffer
int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
// 。。。 根据buffer获取slot,校验是否有效。
// 。。。 共享buffer模式如果共享buffer已经queue状态,直接返回。
if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) {
if (fenceFd >= 0) {
close(fenceFd);
}
return OK;
}
IGraphicBufferProducer::QueueBufferOutput output;
IGraphicBufferProducer::QueueBufferInput input;
// 把参数封装到QueueBufferInput
getQueueBufferInputLocked(buffer, fenceFd, mTimestamp, &input);
applyGrallocMetadataLocked(buffer, input);
sp<Fence> fence = input.fence;
nsecs_t now = systemTime();
// 调用生产者queueBuffer,详见3.3
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
mLastQueueDuration = systemTime() - now;
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer, %d", err);
}
onBufferQueuedLocked(i, fence, output);
return err;
}
3.3 BufferQueueProducer::queueBuffer
这个方法非常长,但是实际做的事并不复杂。
先做了一些参数校验的工作
然后通过slot的数据构造了一个BufferItem对象,修改slot的状态为queued
根据列表里最后一个BufferItem对象的mIsDroppable决定直接添加新Item到队列中还是替换最后一个Item。
mIsDroppable = mCore->mAsyncMode ||
(mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) ||
(mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||
(mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot)
主要还是取决于BufferQueueCore内的一些配置。
然后会唤醒等在mDequeueCondition锁上的线程,这个我们在dequeuBuffer时候看到过。
除此之外会回调frameAvailableListener或者frameReplacedListener,这里的listener在1.9介绍过就是BLASTBufferQueue。
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
int64_t requestedPresentTimestamp;
bool isAutoTimestamp;
android_dataspace dataSpace;
Rect crop(Rect::EMPTY_RECT);
int scalingMode;
uint32_t transform;
uint32_t stickyTransform;
sp<Fence> acquireFence;
bool getFrameTimestamps = false;
// 把input传过来的参数取出来放到变量里
input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
&crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
&getFrameTimestamps);
const Region& surfaceDamage = input.getSurfaceDamage();
const HdrMetadata& hdrMetadata = input.getHdrMetadata();
// 。。。
// 封装了传入的fence
auto acquireFenceTime = std::make_shared<FenceTime>(acquireFence);
// 。。。
sp<IConsumerListener> frameAvailableListener;
sp<IConsumerListener> frameReplacedListener;
int callbackTicket = 0;
uint64_t currentFrameNumber = 0;
BufferItem item;
{ // Autolock scope
std::lock_guard<std::mutex> lock(mCore->mMutex);
// 。。。参数校验
// 如果是共享buffer模式,就只是确保相关变量记录准确
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
BufferQueueCore::INVALID_BUFFER_SLOT) {
mCore->mSharedBufferSlot = slot;
mSlots[slot].mBufferState.mShared = true;
}
// 。。。
// 检测入参中crop是否在graphicBuffer内(crop合法性校验)
const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
Rect croppedRect(Rect::EMPTY_RECT);
crop.intersect(bufferRect, &croppedRect);
if (croppedRect != crop) {
BQ_LOGE("queueBuffer: crop rect is not contained within the "
"buffer in slot %d", slot);
return BAD_VALUE;
}
// Override UNKNOWN dataspace with consumer default
if (dataSpace == HAL_DATASPACE_UNKNOWN) {
dataSpace = mCore->mDefaultBufferDataSpace;
}
// 更新slot里面fence,修改slot状态
mSlots[slot].mFence = acquireFence;
mSlots[slot].mBufferState.queue();
// 帧数统计
++mCore->mFrameCounter;
currentFrameNumber = mCore->mFrameCounter;
mSlots[slot].mFrameNumber = currentFrameNumber;
// 初始化BufferItem的变量, 我们之前提过mQueue里面的对象便是BufferItem
// 所以需要将slot中核心数据存入BufferItem放入到mQueue中。
item.mAcquireCalled = mSlots[slot].mAcquireCalled;
item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
item.mCrop = crop;
item.mTransform = transform &
~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
item.mTransformToDisplayInverse =
(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
item.mScalingMode = static_cast<uint32_t>(scalingMode);
item.mTimestamp = requestedPresentTimestamp;
item.mIsAutoTimestamp = isAutoTimestamp;
item.mDataSpace = dataSpace;
item.mHdrMetadata = hdrMetadata;
item.mFrameNumber = currentFrameNumber;
item.mSlot = slot;
item.mFence = acquireFence;
item.mFenceTime = acquireFenceTime;
// 这个属性决定当item没有及时被消费,新的item来了是否可以替换它。
item.mIsDroppable = mCore->mAsyncMode ||
(mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) ||
(mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||
(mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
item.mSurfaceDamage = surfaceDamage;
item.mQueuedBuffer = true;
item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
item.mApi = mCore->mConnectedApi;
mStickyTransform = stickyTransform;
// 。。。 如果是共享buffer模式,缓存共享buffer数据。
output->bufferReplaced = false;
if (mCore->mQueue.empty()) {
// 如果队列中没有数据,就把新构建的BufferItem入队即可。
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener;
} else {
// 如果队列不为空,我们需要检测最烈最后的Item是否需要被替换
const BufferItem& last = mCore->mQueue.itemAt(
mCore->mQueue.size() - 1);
// 这个变量的逻辑可以参照上面item初始化时候的逻辑,主要取决于mCore的mQueueBufferCanDrop,或者是否是共享buffer。
if (last.mIsDroppable) {
// 。。。
// 替换旧的item
mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
frameReplacedListener = mCore->mConsumerListener;
} else {
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener;
}
}
mCore->mBufferHasBeenQueued = true;
// 前面看dequeueBuffer的时候,如果没有空闲的slot等情况,会等待在这个条件锁上,这里完成了queueBuffer可以唤醒它尝试再去dequeueBuffer
mCore->mDequeueCondition.notify_all();
mCore->mLastQueuedSlot = slot;
// 将部分信息填写至output,回传给上层函数作为结果
output->width = mCore->mDefaultWidth;
output->height = mCore->mDefaultHeight;
output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint;
output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size());
output->nextFrameNumber = mCore->mFrameCounter + 1;
// 。。。
} // Autolock scope
if (!mConsumerIsSurfaceFlinger) {
item.mGraphicBuffer.clear();
}
// Update and get FrameEventHistory.
nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
NewFrameEventsEntry newFrameEventsEntry = {
currentFrameNumber,
postedTime,
requestedPresentTimestamp,
std::move(acquireFenceTime)
};
//回调mConsumerListener的addAndGetFrameTimestamps
addAndGetFrameTimestamps(&newFrameEventsEntry,
getFrameTimestamps ? &output->frameTimestamps : nullptr);
int connectedApi;
sp<Fence> lastQueuedFence;
{ // scope for the lock
std::unique_lock<std::mutex> lock(mCallbackMutex);
while (callbackTicket != mCurrentCallbackTicket) {
mCallbackCondition.wait(lock);
}
// 回调frameAvailableListener 或者 frameReplacedListener
// 1.9我们说过这里的listener就是BLASTBufferQueue
if (frameAvailableListener != nullptr) {
frameAvailableListener->onFrameAvailable(item);
} else if (frameReplacedListener != nullptr) {
frameReplacedListener->onFrameReplaced(item);
}
connectedApi = mCore->mConnectedApi;
lastQueuedFence = std::move(mLastQueueBufferFence);
mLastQueueBufferFence = std::move(acquireFence);
mLastQueuedCrop = item.mCrop;
mLastQueuedTransform = item.mTransform;
++mCurrentCallbackTicket;
mCallbackCondition.notify_all();
}
if (connectedApi == NATIVE_WINDOW_API_EGL) {
// 如果是gpu渲染,这里需要等上一个buffer的fence唤醒。
lastQueuedFence->waitForever("Throttling EGL Production");
}
return NO_ERROR;
}
队列的消费端
讲完了生产者端,再来看看消费者这边的流程。
我们前面讲过queueBuffer会回调BLASTBufferQueue::onFrameAvailable,我们就从这里开始看。
这里做一些前置介绍:Android 12 开始生产者消费者都在app侧,但是最终合成逻辑是在SurfaceFlinger,消费者拿到数据后会存储到一个Trancastion对象里,然后commit到SurfaceFlinger,由SurfaceFLinger使用。不只是渲染内容,窗口大小等属性改变都会通过Transcation来通知SurfaceFlinger。
acquireBuffer流程
4.1 BLASTBufferQueue::onFrameAvailable
mSyncedFrameNumbers不为空说明还有Transcation commit后还没有回调。
mTransactionReadyCallback不为空说明上层需要自己同步处理Transaction,不需要直接提交
如果复用一个Buffer,要先释放mSyncTranscation之前的buffer,检查当前可用Frame数量,看是否需要丢帧。(如果有多个可用帧,直接显示最后一个即可)
acquireNextBufferLocked会获取一个队列中的BufferItem,并根据它构建一个Transcation,如果传入参数为空,则会直接将Transcation apply提交给SurfaceFlinger,否则从入参中返回,详见4.2。
这里之所以有上层自己处理Transaction的情况是因为新版本Android有一套SurfaceSyncGroup的机制,可以用于同步SurfaceView等,这层逻辑在java层。
void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr;
SurfaceComposerClient::Transaction* prevTransaction = nullptr;
{
// buffer被消费者拿到后,主要目的是要构造一个Transaction传给SurfaceFlinger
// SurfaceFlinger通过Transaction来更新各个layer的数据。
// mSyncedFrameNumbers里面存的是已经构建好Transaction但是commit还没有回调
bool waitForTransactionCallback = !mSyncedFrameNumbers.empty();
// 上层调用方需要自己处理新构建的Transaction
const bool syncTransactionSet = mTransactionReadyCallback != nullptr;
if (syncTransactionSet) {
// mAcquireSingleBuffer决定了是否复用同一个mSyncTransaction
// 一般只有SurfaceView才会复用,mAcquireSingleBuffer才会为false
// 如果复用的话,就把之前存在mSyncTransaction里的buffer release了,以便处理新的buffer
if (!mAcquireSingleBuffer) {
auto bufferData = mSyncTransaction->getAndClearBuffer(mSurfaceControl);
if (bufferData) {
// releaseBuffer流程我们后面再看。
releaseBuffer(bufferData->generateReleaseCallbackId(),
bufferData->acquireFence);
}
}
if (waitForTransactionCallback) {
// 如果当前有Transaction已经commit却还没有回调,而且还有可用的Frame
// 这时候就要释放掉可用的Frame,因为新的Frame已经准备好(就是丢帧了)
while (mNumFrameAvailable > 0) {
acquireAndReleaseBuffer();
}
} else {
// 等待前面的帧处理。
while (mNumFrameAvailable > 0) {
BQA_LOGD("waiting until no queued buffers");
mCallbackCV.wait(_lock);
}
}
}
// 可用Frame记数
mNumFrameAvailable++;
// 如果有两个以上可用帧,就释放一个(丢帧了)
if (waitForTransactionCallback && mNumFrameAvailable >= 2) {
acquireAndReleaseBuffer();
}
// 如果上层需要自己处理Transcation
if (syncTransactionSet) {
// 记录当前帧需要等待commit回调
mSyncedFrameNumbers.emplace(item.mFrameNumber);
while (acquireNextBufferLocked(mSyncTransaction) == BufferQueue::NO_BUFFER_AVAILABLE) {
BQA_LOGD("waiting for available buffer");
// 在锁上等待生产者
mCallbackCV.wait(_lock);
}
// 向SurfaceFlinger注册回调函数
incStrong((void*)transactionCommittedCallbackThunk);
mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
static_cast<void*>(this));
// 重置变量
if (mAcquireSingleBuffer) {
prevCallback = mTransactionReadyCallback;
prevTransaction = mSyncTransaction;
mTransactionReadyCallback = nullptr;
mSyncTransaction = nullptr;
}
} else if (!waitForTransactionCallback) {
// 获取BufferItem,构建Transcation并且直接提交
acquireNextBufferLocked(std::nullopt);
}
}
if (prevCallback) {
// 上层自己处理Transaction的回调。
prevCallback(prevTransaction);
}
}
4.2 acquireNextBufferLocked
该方法主要是通过mBufferItemConsumer->acquireBuffer获取一个队列的BufferItem
然后根据获取的BufferItem构造出Transaction
如果入参transaction不为空,则将新构造的Transcation通过入参返回,否则直接将Transaction.apply异步的方式传给SurfaceFlinger。
setBuffer里面会调用setReleaseBufferCallback,注册release回调,SurfaceFlinger是通过这个回调通知Client releaseBuffer的。
status_t BLASTBufferQueue::acquireNextBufferLocked(
const std::optional<SurfaceComposerClient::Transaction*> transaction) {
// 。。。检查是否有可用的帧
// 构造一个Transaction, 如果有入参,就用入参。
SurfaceComposerClient::Transaction localTransaction;
bool applyTransaction = true;
SurfaceComposerClient::Transaction* t = &localTransaction;
if (transaction) {
t = *transaction;
applyTransaction = false;
}
BufferItem bufferItem;
// 调用acquireBuffer,获取生产者生产的BufferItem。详见4.3
status_t status =
mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
// 。。。异常处理
auto buffer = bufferItem.mGraphicBuffer;
mNumFrameAvailable--;
BBQ_TRACE("frame=%" PRIu64, bufferItem.mFrameNumber);
// 如果bufferItem里没有图元buffer,直接释放BufferItem后返回
if (buffer == nullptr) {
mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
BQA_LOGE("Buffer was empty");
return BAD_VALUE;
}
// 。。。
// 更新mLastBufferInfo,在计算脏区会用到
mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
bufferItem.mScalingMode, crop);
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
// 根据BufferItem里面的内容填充Transaction
// setBuffer里面会调用setReleaseBufferCallback,注册release回调,SurfaceFlinger是通过这个回调通知Client releaseBuffer的
t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, mProducerId,
releaseBufferCallback);
t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
// 设置Transaction回调。
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
if (mUpdateDestinationFrame) {
t->setDestinationFrame(mSurfaceControl, Rect(mSize));
} else {
const bool ignoreDestinationFrame =
bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE;
t->setFlags(mSurfaceControl,
ignoreDestinationFrame ? layer_state_t::eIgnoreDestinationFrame : 0,
layer_state_t::eIgnoreDestinationFrame);
}
t->2(mSurfaceControl, crop);
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
if (!bufferItem.mIsAutoTimestamp) {
t->setDesiredPresentTime(bufferItem.mTimestamp);
}
// 抛弃mPendingFrameTimelines中帧序列号小于当前处理的BufferItem的项。
while (!mPendingFrameTimelines.empty() &&
mPendingFrameTimelines.front().first < bufferItem.mFrameNumber) {
ATRACE_FORMAT_INSTANT("dropping stale frameNumber: %" PRIu64 " vsyncId: %" PRId64,
mPendingFrameTimelines.front().first,
mPendingFrameTimelines.front().second.vsyncId);
mPendingFrameTimelines.pop();
}
// 获取当前BufferItem对应的FrameTimelineInfo,里面包含一些时间信息。
// 如当前帧开始渲染时间,vsyncId等
if (!mPendingFrameTimelines.empty() &&
mPendingFrameTimelines.front().first == bufferItem.mFrameNumber) {
ATRACE_FORMAT_INSTANT("Transaction::setFrameTimelineInfo frameNumber: %" PRIu64
" vsyncId: %" PRId64,
bufferItem.mFrameNumber,
mPendingFrameTimelines.front().second.vsyncId);
t->setFrameTimelineInfo(mPendingFrameTimelines.front().second);
mPendingFrameTimelines.pop();
}
{
std::lock_guard _lock{mTimestampMutex};
auto dequeueTime = mDequeueTimestamps.find(buffer->getId());
if (dequeueTime != mDequeueTimestamps.end()) {
Parcel p;
p.writeInt64(dequeueTime->second);
t->setMetadata(mSurfaceControl, gui::METADATA_DEQUEUE_TIME, p);
mDequeueTimestamps.erase(dequeueTime);
}
}
// mPendingTransactions里的Transcation是通过调用mergeWithNextTransaction添加的
// 把多个帧需要的提交合并一起提交
mergePendingTransactions(t, bufferItem.mFrameNumber);
if (applyTransaction) {
// 提交给SurfaceFlinger
t->setApplyToken(mApplyToken).apply(false, true);
mAppliedLastTransaction = true;
mLastAppliedFrameNumber = bufferItem.mFrameNumber;
} else {
t->setBufferHasBarrier(mSurfaceControl, mLastAppliedFrameNumber);
mAppliedLastTransaction = false;
}
// 。。。
return OK;
}
4.3 BufferItemConsumer::acquireBuffer
主要是调用了ConsumeBase::acquireBufferLocked,此外还等待了fence,这个fence主要是用来同步生产者使用gpu渲染。
status_t BufferItemConsumer::acquireBuffer(BufferItem *item,
nsecs_t presentWhen, bool waitForFence) {
status_t err;
if (!item) return BAD_VALUE;
Mutex::Autolock _l(mMutex);
// 调用ConsumeBase::acquireBufferLocked,相见4.4
err = acquireBufferLocked(item, presentWhen);
// 。。。
// 这里要等待fence,这个fence是之前生产者传过来的,要等待gpu渲染完成。
if (waitForFence) {
err = item->mFence->waitForever("BufferItemConsumer::acquireBuffer");
if (err != OK) {
BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
strerror(-err), err);
return err;
}
}
item->mGraphicBuffer = mSlots[item->mSlot].mGraphicBuffer;
return OK;
}
4.4 ConsumeBase::acquireBufferLocked
主要就是调用了BufferQueueConsumer::acquireBuffer来获取Buffer。
status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
nsecs_t presentWhen, uint64_t maxFrameNumber) {
// 。。。
// 调用BufferQueueConsumer::acquireBuffer,详见4.5
status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
if (err != NO_ERROR) {
return err;
}
if (item->mGraphicBuffer != nullptr) {
if (mSlots[item->mSlot].mGraphicBuffer != nullptr) {
freeBufferLocked(item->mSlot);
}
mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
}
mSlots[item->mSlot].mFrameNumber = item->mFrameNumber;
mSlots[item->mSlot].mFence = item->mFence;
return OK;
}
4.5 BufferQueueConsumer::acquireBuffer
入参expectedPresent代表期望的时间,只有期望时间小于这个的buffer才是可以被使用的。maxFrameNumber代表最大的帧序号,只有帧序号小于这个的才可以被执行。
先根据传入的参数判断队列中第二个BufferItem是否可以被消费,如果可以的话,第一个BufferItem就可以抛弃了,根据这个逻辑循环遍历队列。
再检测最前面我们要用来消费的BufferItem是否满足入参的时间和帧序列要求,不满足就返回PRESENT_LATER错误码。
把队列最前面的BufferItem取出放到outBuffer,修改Buffer状态到acquired。
之前抛弃的帧,回调对应次数onBufferReleased
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber) {
ATRACE_CALL();
int numDroppedBuffers = 0;
sp<IProducerListener> listener;
{
std::unique_lock<std::mutex> lock(mCore->mMutex);
// 统计acquired状态buffer个数
int numAcquiredBuffers = 0;
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isAcquired()) {
++numAcquiredBuffers;
}
}
// 。。。看acquired状态的buffer有没有到上限
bool sharedBufferAvailable = mCore->mSharedBufferMode &&
mCore->mAutoRefresh && mCore->mSharedBufferSlot !=
BufferQueueCore::INVALID_BUFFER_SLOT;
// 检测队列中是否有BufferItem可用
if (mCore->mQueue.empty() && !sharedBufferAvailable) {
return NO_BUFFER_AVAILABLE;
}
BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
// 这里是用来检测是否需要抛弃一些帧的。
if (expectedPresent != 0 && !mCore->mQueue.empty()) {
// 如果队列中有大于一个bufferItem,就检测一下是否需要丢帧
while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
// 获取队列里第二个BufferItem
const BufferItem& bufferItem(mCore->mQueue[1]);
// 如果入参最大帧序列比当前帧序列小,说明消费者还没准备好消费这个帧,所以不丢弃。
if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
break;
}
nsecs_t desiredPresent = bufferItem.mTimestamp;
// 如果第二个bufferItem期望到时间还没有到,
if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
desiredPresent > expectedPresent) {
break;
}
if (!front->mIsStale) {
// 如果当前第二个bufferItem都已经到执行时间了,那就把第一个抛弃了。
mSlots[front->mSlot].mBufferState.freeQueued();
// 。。。 处理共享Buffer模式的情况
if (mCore->mBufferReleasedCbEnabled) {
listener = mCore->mConnectedProducerListener;
}
// 记录丢弃BuffferItem个数
++numDroppedBuffers;
}
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
}
// 根据入参检测第一个buffer是否到了可以使用的时间
nsecs_t desiredPresent = front->mTimestamp;
bool bufferIsDue = desiredPresent <= expectedPresent ||
desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
bool consumerIsReady = maxFrameNumber > 0 ?
front->mFrameNumber <= maxFrameNumber : true;
if (!bufferIsDue || !consumerIsReady) {
// 如果第一个Buffer的时间还没有到,返回状态码PRESENT_LATER
return PRESENT_LATER;
}
}
int slot = BufferQueueCore::INVALID_BUFFER_SLOT;
if (sharedBufferAvailable && mCore->mQueue.empty()) {
// 如果是共享Buffer模式,并且队列是空的,如果当前正在分配Buffer,就需要等分配完后继续
mCore->waitWhileAllocatingLocked(lock);
slot = mCore->mSharedBufferSlot;
// 。。。将共享Buffer的数据拷贝到出参outBuffer
} else if (acquireNonDroppableBuffer && front->mIsDroppable) {
BQ_LOGV("acquireBuffer: front buffer is not droppable");
return NO_BUFFER_AVAILABLE;
} else {
// 正常走这里,将从队列最前面获取到的BufferItem拷贝到outBuffer
slot = front->mSlot;
*outBuffer = *front;
}
if (!outBuffer->mIsStale) {
mSlots[slot].mAcquireCalled = true;
// 修改Buffer状态
if (mCore->mQueue.empty()) {
mSlots[slot].mBufferState.acquireNotInQueue();
} else {
mSlots[slot].mBufferState.acquire();
}
mSlots[slot].mFence = Fence::NO_FENCE;
}
// 如果这个buffer之前已经被消费者acquire,防止mGraphicBuffer被重复map
if (outBuffer->mAcquireCalled) {
outBuffer->mGraphicBuffer = nullptr;
}
mCore->mQueue.erase(front);
// 前面可能丢弃了一些帧,就会释放出一些buffer,这里可以唤醒dequeueBuffer的锁。
mCore->mDequeueCondition.notify_all();
}
if (listener != nullptr) {
// 前面可能丢弃了一些帧,这里需要回调对应次数的onBufferReleased
for (int i = 0; i < numDroppedBuffers; ++i) {
listener->onBufferReleased();
}
}
return NO_ERROR;
}
releaseBuffer流程
介绍完了acquireBuffer,我们再来看看releaseBuffer的流程。
在4.2的流程中,我们提到为Transaction去setBuffer的时候我们会调用setReleaseBufferCallback,releaseBuffer就是SurfaceFlinger通过这里来回调的。
我们就从回调这里开始看
5.1 releaseBufferCallback
void BLASTBufferQueue::releaseBufferCallback(
const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount) {
std::lock_guard _lock{mMutex};
BBQ_TRACE();
// 详见5.2
releaseBufferCallbackLocked(id, releaseFence, currentMaxAcquiredBufferCount,
false /* fakeRelease */);
}
5.2 releaseBufferCallbackLocked
会对EGL渲染的队列保留一些缓冲区(根据注释,当配置刷新率低于最大刷新率时这样可以防止更高延迟,具体什么原理也没有去研究了)
主要是调用了releaseBuffer去释放Buffer
void BLASTBufferQueue::releaseBufferCallbackLocked(
const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount, bool fakeRelease) {
// 计算需要保留的缓冲区数量(当配置刷新率低于最大刷新率时这样可以防止更高延迟)
const auto it = mSubmitted.find(id);
const bool isEGL = it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL;
if (currentMaxAcquiredBufferCount) {
mCurrentMaxAcquiredBufferCount = *currentMaxAcquiredBufferCount;
}
const uint32_t numPendingBuffersToHold =
isEGL ? std::max(0, mMaxAcquiredBuffers - (int32_t)mCurrentMaxAcquiredBufferCount) : 0;
auto rb = ReleasedBuffer{id, releaseFence};
if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) {
mPendingRelease.emplace_back(rb);
if (fakeRelease) {
BQA_LOGE("Faking releaseBufferCallback from transactionCompleteCallback %" PRIu64,
id.framenumber);
BBQ_TRACE("FakeReleaseCallback");
}
}
while (mPendingRelease.size() > numPendingBuffersToHold) {
const auto releasedBuffer = mPendingRelease.front();
mPendingRelease.pop_front();
// 调用releaseBuffer,详见5.3
releaseBuffer(releasedBuffer.callbackId, releasedBuffer.releaseFence);
// 如果没有同步的帧在处理,直接调用acquireNextBufferLocked去apply下一帧
if (mSyncedFrameNumbers.empty()) {
acquireNextBufferLocked(std::nullopt);
}
}
mCallbackCV.notify_all();
}
5.3 BLASTBufferQueue::releaseBuffer
调用mBufferItemConsumer->releaseBuffer
void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId,
const sp<Fence>& releaseFence) {
auto it = mSubmitted.find(callbackId);
if (it == mSubmitted.end()) {
BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s",
callbackId.to_string().c_str());
return;
}
mNumAcquired--;
// 调用BufferItemConsumer::releaseBuffer,详见5.4
mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
mSubmitted.erase(it);
mSyncedFrameNumbers.erase(callbackId.framenumber);
}
5.4 BufferItemConsumer::releaseBuffer
把releaseFence里面的fence更新到BufferItem的fence,dequeueBuffer时候需要等待这个fence,虽然cpu角度SurfaceFlinger已经使用完成这个Buffer,但是可能gpu或者hwc还在使用。
主要逻辑在releaseBufferLocked,详见5.5
status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
const sp<Fence>& releaseFence) {
status_t err;
Mutex::Autolock _l(mMutex);
// 把releaseFence里面的fence更新到BufferItem的fence
err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence);
if (err != OK) {
BI_LOGE("Failed to addReleaseFenceLocked");
}
// 调用releaseBufferLocked,详见5.5
err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY,
EGL_NO_SYNC_KHR);
// 。。。
return err;
}
5.5 ConsumerBase::releaseBufferLocked
调用BufferQueueConsumer::releaseBuffer
status_t ConsumerBase::releaseBufferLocked(
int slot, const sp<GraphicBuffer> graphicBuffer,
EGLDisplay display, EGLSyncKHR eglFence) {
// 。。。
// 调用BufferQueueConsumer::releaseBuffer,详见5.6
status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber,
display, eglFence, mSlots[slot].mFence);
if (err == IGraphicBufferConsumer::STALE_BUFFER_SLOT) {
freeBufferLocked(slot);
}
mPrevFinalReleaseFence = mSlots[slot].mFence;
mSlots[slot].mFence = Fence::NO_FENCE;
return err;
}
5.6 BufferQueueConsumer::releaseBuffer
主要工作就是把slot号放到空闲队列里。
然后回调listener->onBufferReleased
status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
EGLSyncKHR eglFence) {
// 。。。
sp<IProducerListener> listener;
{ // Autolock scope
std::lock_guard<std::mutex> lock(mCore->mMutex);
// 帧号因为缓冲区重新分配发生变化,忽略releaseBuffer。
if (frameNumber != mSlots[slot].mFrameNumber &&
!mSlots[slot].mBufferState.isShared()) {
return STALE_BUFFER_SLOT;
}
// 。。。要release的Buffer如果不是acquired状态,直接返回
mSlots[slot].mEglDisplay = eglDisplay;
mSlots[slot].mEglFence = eglFence;
mSlots[slot].mFence = releaseFence;
mSlots[slot].mBufferState.release();
if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) {
mSlots[slot].mBufferState.mShared = false;
}
// 把buffer放到空闲队列里。
if (!mSlots[slot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(slot);
mCore->mFreeBuffers.push_back(slot);
}
if (mCore->mBufferReleasedCbEnabled) {
listener = mCore->mConnectedProducerListener;
}
mCore->mDequeueCondition.notify_all();
} // Autolock scope
// 回调listener.onBufferReleased
if (listener != nullptr) {
listener->onBufferReleased();
}
return NO_ERROR;
}
小结
我们这篇文章主要介绍了BlastBufferQueue队列以及生产者消费者对象的构造,一些核心的变量含义,以及他们的核心流程dequeuBuffer,queueBuffer,acquireBuffer,releaseBuffer。