BufferQueue
BufferQueue要解決的是生產(chǎn)者和消費(fèi)者的同步問(wèn)題盔夜,應(yīng)用程序產(chǎn)生畫(huà)面缩擂,SurfaceFlinger 消費(fèi)畫(huà)面谷浅;SurfaceFlinger 生成畫(huà)面而HWC service 消費(fèi)畫(huà)面涂滴;用來(lái)存儲(chǔ)這些畫(huà)面的區(qū)域我們稱(chēng)為緩沖區(qū)胆建,為此需要按照下面需求設(shè)計(jì):
- 需要有緩沖區(qū)供生產(chǎn)者消費(fèi)者使用
- 生產(chǎn)者生產(chǎn)完成需要能夠通知到消費(fèi)者
- 生產(chǎn)者一般為app街州,消費(fèi)者是 sf,因此需要拷貝跨進(jìn)程通信的問(wèn)題
下面我們以應(yīng)用程序?yàn)樯a(chǎn)者玻孟,SurfaceFlinger 為消費(fèi)者為例唆缴,了解一下BufferQueue 的內(nèi)部設(shè)計(jì)
BufferState 的切換
在BufferQueue 的設(shè)計(jì)中,Buffer 存在下面幾種狀態(tài):
FREE:表示該Buffer 是空閑的黍翎,可以給到應(yīng)用程序面徽,由應(yīng)用程序來(lái)繪圖
DEQUEUED:表示Buffer 的控制權(quán)已經(jīng)交給了應(yīng)用程序側(cè),這個(gè)狀態(tài)下應(yīng)用程序可以在上面繪圖了
QUEUED:表示該Buffer已經(jīng)由應(yīng)用程序繪圖完成匣掸,Buffer 的控制權(quán)已經(jīng)回到SurfaceFlinger 了
ACQUIRED:表示該Buffer 已經(jīng)交給 HWC service去合成了趟紊,這個(gè)時(shí)候控制權(quán)已經(jīng)給到HWC service了
Buffer 的初始狀態(tài)是Free
- 當(dāng)生產(chǎn)者通過(guò)dequeueBuffer 來(lái)申請(qǐng)Buffer 成功時(shí),buffer 的狀態(tài)變?yōu)?QEQUEUED
- 應(yīng)用程序繪制完成后通過(guò)queueBuffer 把BufferState 狀態(tài)改為 QUEUED 狀態(tài)
- SurfaceFlinger 通過(guò) acquiredBuffer 把 Buffer 拿去給 HWC service合成碰酝,這時(shí)的Buffer 變?yōu)?ACQUIRED 狀態(tài)
-
合成完成后通過(guò) release buffer 把 Buffer 狀態(tài)改為FREE狀態(tài)霎匈,
狀態(tài)切換圖如下圖所示:
從時(shí)間軸上一個(gè)Buffer 的變化過(guò)程是:
FREE->DEQUEUED->QUEUED->ACQUIRED->FREE
BufferSlot
每一個(gè)應(yīng)用程序圖層在SurfaceFlinger 里稱(chēng)為一個(gè)Layer,每個(gè)Layer都有一個(gè)獨(dú)特的BufferQueue送爸,每個(gè) BufferQueue都會(huì)有多個(gè)Buffer铛嘱,目前Android 系統(tǒng)上單圖層最多支持 64個(gè)Buffer
BufferSlot 的定義如下:
framework/native/libs/gui/include/gui/BufferQueueDefs.h
namespace android {
class BufferQueueCore;
namespace BufferQueueDefs {
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
} // namespace BufferQueueDefs
} // namespace android
SlotsType 被 typedef 定義成了數(shù)組類(lèi)型,數(shù)組元素是BufferSlot袭厂,數(shù)組的大小為NUM_BUFFER_SLOTS(64)
BufferSlot 是對(duì)GraphicBuffer 的封裝墨吓,重要成員如下:
struct BufferSlot {
.....
BufferState mBufferState; //當(dāng)前的 Buffer 狀態(tài),F(xiàn)REE/DEQUEUED/QUEUED/ACQUIRED
sp<GraphicBuffer> mGraphicBuffer; // 代表了Buffer 存儲(chǔ)空間
uint64_t mFrameNumber; //表示這個(gè)slot被queued的編號(hào)纹磺,在應(yīng)用調(diào)dequeueBuffer申請(qǐng)slot時(shí)會(huì)參考該值
sp<Fence> mFence;
}
64 個(gè) BufferSlot 可以分為兩部分帖烘,usedslot(使用中的) 和 unusedlot(未使用中的)
usedslot = active slot + unactive slot
而usedslot又可以分為 active slot 和 unactive slot,處在 DEQUEUED橄杨,QUEUED蚓让,ACQUIRED狀態(tài)的被稱(chēng)為active slot,剩下FREE狀態(tài)的稱(chēng)為unactive Slots讥珍;
所有activeSlots都是有人正在使用中的 slot,使用者可以是生產(chǎn)者也可以是消費(fèi)者
unactive slot = Free state slot = mFreeBuffers + mFreeSlots
而Free 狀態(tài)的slot 根據(jù)是否為其分配內(nèi)存可以分為mFreeBuffers 和 mFreeSlots
- mFreeBuffers:已經(jīng)分配過(guò)內(nèi)存的
- mFreeSlots:沒(méi)有分配過(guò)內(nèi)存的
如果從代碼中看到mFreeSlots中拿出一個(gè) Bufferslot 那說(shuō)明這個(gè)Bufferslot 還沒(méi)有配置過(guò)GraphicBuffer的窄瘟,這個(gè)slot 可能第一次用到
Buffer 的分配流程
framework/native/libs/gui/Surface.cpp
- 應(yīng)用第一次dequeueBuffer前會(huì)通過(guò)connect接口和SurfaceFlinger 連接
int Surface::connect(
int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
ATRACE_CALL();
...
int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
}
- 調(diào)用 dequeueBuffer時(shí)會(huì)先調(diào)用requestBuffer
result 標(biāo)志第一次會(huì)帶 BUFFER_NEEDS_REALLOCATION 標(biāo)志
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
ATRACE_CALL();//這里可以在systrace中看到
......
//這里嘗試去dequeueBuffer,因?yàn)檫@時(shí)SurfaceFlinger對(duì)應(yīng)Layer的slot還沒(méi)有分配buffer,這時(shí)SurfaceFlinger會(huì)回復(fù)的flag會(huì)有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返回的結(jié)果里帶有BUFFER_NEEDS_REALLOCATION標(biāo)志就會(huì)發(fā)出一次requestBuffer
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
......
}
......
}
- 因?yàn)閼?yīng)用側(cè) Surface 對(duì)象中 包含的是 GraphicBufferProducer 的 binder client端對(duì)象衷佃,所以實(shí)際的調(diào)用是在
Surfaceflinger 進(jìn)程的 server 端 BufferQueueProducer.cpp,注意dequeueBuffer 實(shí)際返回的是一個(gè)空間 slot
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, usage))//檢查是否已分配了GraphicBuffer
{
......
returnFlags |= BUFFER_NEEDS_REALLOCATION;//發(fā)現(xiàn)需要分配buffer,置個(gè)標(biāo)記
}
......
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
......
//新創(chuàng)建一個(gè)新的GraphicBuffer給到對(duì)應(yīng)的slot
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
width, height, format, BQ_LAYER_COUNT, usage,
{mConsumerName.string(), mConsumerName.size()});
......
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;//把GraphicBuffer給到對(duì)應(yīng)的slot
......
}
......
return returnFlags;//注意在應(yīng)用第一次請(qǐng)求buffer, dequeueBuffer返回時(shí)對(duì)應(yīng)的GraphicBuffer已經(jīng)創(chuàng)建完成并給到了對(duì)應(yīng)的slot上蹄葱,但返回給應(yīng)用的flags里還是帶有BUFFER_NEEDS_REALLOCATION標(biāo)記的
}
根據(jù) client 端的調(diào)用氏义,會(huì)繼續(xù)調(diào)用到requestBuffer
status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ATRACE_CALL();
mSlots[slot].mRequestBufferCalled = true;
*buf = mSlots[slot].mGraphicBuffer;
return NO_ERROR;
}
tips: 為什么不在 dequeueBuffer時(shí),直接返回 GraphicBuffer 對(duì)象图云,而是返回一個(gè)空閑的 slot惯悠,再調(diào)用requestBuffer去獲得一個(gè) GraphicBuffer?
因?yàn)檫@個(gè)接口調(diào)用太頻繁了,比如在90FPS的設(shè)備上竣况,一秒鐘該接口要執(zhí)行90次克婶,太頻繁了,而且這個(gè)信息只需要傳遞一次就可以了,如果每次這個(gè)接口都要帶上GraphicBuffer的信息情萤,傳輸了很多冗余數(shù)據(jù)鸭蛙,所以不如加入一個(gè)新的api(requestBuffer)來(lái)完成GraphicBuffer傳遞的事情
GraphicBuffer 繼承了 Parcel 對(duì)象,可以通過(guò)Binder跨進(jìn)程傳遞