BufferQueue
BufferQueue要解决的是生产者的同步问题,应用程序生产画面,SurfaceFlinger消费画面,SurfaceFlinger生产画面而HWCService消费画面。用来存储这些画面的存储区我们称其为帧缓冲区buffer,下面我们以应用程序作为生产者,SurfaceFlinger作为消费者为例来了解一下BufferQueue的内部设计。
Buffer State的切换
在Buffer Queue的设计中,一个buffer有以下几种状态:
FREE:表示该buffer可以给到应用程序,由应用程序来绘画
Dequeued:表示该buffer的控制权已经交给到应用程序侧,这个状态下应用程序可以在上面绘图了
Queued:表示buffer已经由应用程序绘画完成,buffer的控制权已经回到SurfaceFlinger手上
QCQUIRED:表示该buffer已经交给HWC service去合成了,这时控制权已经到HWC Service了
Buffer初始态为FREE,当生产者通过dequeueBuffer来申请buffer成功时,buffer状态变成Dequeued状态,应用画图完成后通过queueBuffer将buffer状态变为了Queued状态,当SurfaceFlinger通过acquireBuffer操作将buffer拿去给HWC Service合成,这时buffer状态变为ACQUIRED状态,合成完成后通过releaseBuffer把buffer状态重新改为FREE状态。状态切换如下图所示:
从时间轴上来看一个buffer的状态总是这样循环变化
FREE–>DEQUEUED–>QUEUED–>FREE
应用程序在DEQUEUED状态下绘图,而HWC Service在状态为ACQUIRED状态下合成
BufferSlot
每一个应用程序的图层在SurfaceFlinger里称为一个Layer,而每个Layer都拥有一个独立的BufferQueue,每个BufferQueue都有多个Buffer,Android系统上目前支持每个Layer最多64个buffer,这个最大值被定义在frameworks/native/gui/BufferQueueDefs.h,每个buffer用一个结构体BufferSlot来代表。
每个BufferSlot里主要有如下重要成员:
struct BufferSlot{
......
BufferState mBufferState;//代表当前Buffer的状态 FREE/DEQUEUED/QUEUED/ACQUIRED
....
sp<GraphicBuffer> mGraphicBuffer;//代表了真正的buffer的存储空间
......
uint64_t mFrameNumber;//表示这个slot被queued的编号,在应用调dequeueBuffer申请slot时会参考该值
......
sp<Fence> mFence;//在Fence一章再来看它的作用
.....
}
64个BufferSlot可以分成俩个部分,used Slots和Unused Slot就是使用未使用的,而Used Slots又可以分为Active Slots和UnActive Slots ,处在Dequeued,queued,ACQUIRED状态的被称为Active Slots,剩下FREE状态的称为UnActive Slots,所以所有Active Slots都是正在有人使用中的slot,使用者可能是生产者也可能是消费者。而FREE状态的Slot根据是否已经为其分配内存分为两个部分,一是已经分配过内存的,在Android源码中称mFreeBuffers,没有分配过内存的称为mFreeSlots, 所以如果我们在代码中看到是从mFreeSlots里拿出一个BufferSlot那说明这个BufferSlot是还没有配置GraphicBuffer的, 这个slot可能是第一次被使用到。其分类如下图所示:
我们来看一下,应用上帧时SurfaceFlinger是如何管理分配这些Slot的。
应用侧对图层buffer的操作接口如下文件:
应用第一次dequeueBuffer前会通过connect接口和SurfaceFlinger建立连接
int Surface::connect(int api, const sp<IProducerListener>&listener, bool reportBufferRemoval){
ATRACE_CALL();//应用第一次上帧前可以在trace 中看到这个
......
int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);//这里通过binder调用和SurfaceFlinger建立联系
......
}
应用第一次dequeueBuffer时会先调用requestBuffer:文章来源:https://www.toymoban.com/news/detail-534652.html
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
ATRACE_CALL();//这里可以在systrace中看到
......
//这里尝试去dequeueBuffer,因为这时SurfaceFlinger对应Layer的slot还没有分配buffer,这时SurfaceFlinger会回复的flag会有BUFFER_NEEDS_REALLOCATION
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
reqFormat, reqUsage, &mBufferAge,
enableFrameTimestamps?&frameTimestamps:nullptr);
......
if((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
......
//这里检查到dequeueBuffer返回的结果里带有BUFFER_NEEDS_REALLOCATION标志就会发出一次requestBuffer
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
......
}
......
}
在SurfaceFinger这端,第一次收到DequeueBuffer时发现分配出来的slot没有Graphic,这时会去申请对应的Buffer文章来源地址https://www.toymoban.com/news/detail-534652.html
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) {
if ((buffer == NULL) ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT,
到了这里,关于Android 画面显示流程二的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!