BufferQueue原創(chuàng) - fence 的流轉(zhuǎn)

首先理解一下什么是 fence.

fence 可以理解為 一個有時間線的fd. 是的, 可以認為 fence 本質(zhì)上是一個 fd, 是以 fd 的形式在各個進程之間流轉(zhuǎn)的, 所以一般來說 要接收一個 fence 的話, 我們都是傳遞的一個 int 的地址, 本質(zhì)上就是傳的這個 fd.

假設 A 進程剛開始使用 B 進程生產(chǎn)的Buffer, 然后就馬上把這個 Buffer 交給B進程再次生產(chǎn),同時會傳遞一個Fence給B進程, B進程再次生產(chǎn)的時候, 就需要根據(jù)Fence來判斷能不能復用這個Buffer.

具體流程是:
A模塊在初始化的時候會創(chuàng)建一個timeline
struct sw_sync_timeline *timeline = sw_sync_timeline_create("test-timeline");

A收到B送的Buffer, 就會創(chuàng)建Fence, 然后把Buffer和Fence傳遞給B

對于每一個Buffer, A進程會根據(jù)自己的timeline創(chuàng)建一個節(jié)點PT, 這個節(jié)點的PT有一個value, 這個value是一個全局的, 每創(chuàng)建一個pt節(jié)點, value的值就會+1, 這樣可以確保 后創(chuàng)建的節(jié)點的value值永遠比前面的大
`struct sync_pt *pt = sw_sync_pt_create(timeline, val);

創(chuàng)建完這個pt節(jié)點, 就根據(jù)這個pt節(jié)點來創(chuàng)建一個 fence
struct sync_fence *fence = sw_sync_fence_create("test-fence",pt);

然后獲取一個現(xiàn)在不被使用的fd
int fd = get_unused_fd();

把這個fence和fd綁定
sync_fence_install(fence,fd);

每使用完一個Buffer, 就按順序signal timeline上的節(jié)點
sw_sync_timeline_inc(timeline, 1);

模塊B想要復用該Buffer的時候,需要先取得fence, 然后看一下這個fence是否被signal
struct fence *fence = sw_file_get_fence(fd); //根據(jù)fd取得fence

等待fence被signal
sync_fence_wait(fence, 1000);

fence 分為兩類, 生產(chǎn)者產(chǎn)生的 fence 叫做 acquireFence(不優(yōu)雅,應該叫 producerFence), 消費者產(chǎn)生的 fence 叫做 releaseFence (不恰當, 應該叫做 consumerFence). 不過這都無所謂。
另一個角度看, 當寫入一個Buffer的時候, 要帶acquireFence還給BQ. 當讀取完一個Buffer的時候要帶releaseFence還給BQ.
再換一個角度, 當寫入一個Buffer之前, 要check releaseFence. 但讀取一個Buffer之前要check acquireFence.
這兩類fence都是在把Buffer還給 BufferQueue 的時候增加的。

那我們就先看一下acquireFence的過程。 首先 Surface.cpp 的 queueBuffer 中, 會帶有 fenceFd, 這個 fenceFd是在哪里賦值的呢?在Camera3OutputStreamreturnBufferCheckedLocked方法中, 我們看到, Provider返回的這個 camera_stream_buffer 就帶有fence, 自帶 acquire_fencerelease_fence, 我們這里用到的是release_fence.
這里為啥要用release_fence呢? Surface作為生產(chǎn)者, 往BufferQueue中 queueBuffer 的時候應該帶著 acquireFence 呀。
這個是因為 acquireFence 和 releaseFence 都是 BufferQueue 的叫法。。。。 bufferQueue會把 queueBuffer 的時候帶的 fence 叫做 acquireFence...
但是對于很多底層的硬件來說, 當不是這個硬件生產(chǎn)的Buffer離開這個硬件的時候, 都會調(diào)用一些 release 方法, 然后往對應的數(shù)據(jù)結(jié)構(gòu)的 relasexxx 屬性上, 所以就造成了上面這種情況。

那我們在看一下 releaseFence 的過程, 在 android_media_ImageReader.cppImageReader_imageRelease中, 會先調(diào)用 Image_unlockIfLocked來獲取 releaseFence, 最終調(diào)用到 GraphicBuffer 的 ublockAsync來獲取Fence, 在調(diào)用到 GraphicBufferMapperunlockAsync獲取 Fence .

看一下在C++中的使用。

  1. SurfaceComposerClient 是 SurfaceFlinger的 binder 代理, 可以通過它來讓 SurfaceFlinger 分配buffer.
  2. SurfaceComposerClient 的 createSurface 方法, 會創(chuàng)建一個 SurfaceControl, SurfaceControl 是 Surface 的包裝類。
  3. Surface 和 ANativeWindow 又是等價的。 要使用 ANativeWindow 申請 Buffer, 還有一些必要的設置, 這是由于這里的Buffer是從SurfaceFlinger來的, 所以缺少對應的參數(shù)。 ANativeWindow由于是真正和底層硬件打交道的, 所以我們必須要 通過native_window_api_connect來讓它和具體的硬件關聯(lián)。 然后native_window_set_buffers_format來設置Window的格式, native_window_set_usage來設置用途, native_window_set_buffers_user_dimensions來設置展示大小, native_window_set_scaling_mode來設置縮放模式, 一般都需要設置這些參數(shù)。
    然后才是調(diào)用 dequeueBuffer來獲取一個Buffer.
    獲得了buffer之后, 就可以包裝成 GraphicBuffer, 然后 lock出來 buffer的地址, 進行數(shù)據(jù)填充了。
    填充完之后進行unlock
    最后將其queueBuffer到BufferQueue中, 就可以被消費者消費了。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容