AndroidQ 圖形系統(5)Fence機制簡介

前面分析dequeueBufferqueueBuffer時,看到Fence都是跳過的,只知道這是一種資源同步機制,具體不瞭解,這兩天在網上查閱了相關資料,對Fence機制有了一個大致的瞭解,本篇總結一下。

什麼是同步?java中有個synchronized關鍵字,被synchronized修飾的方法同一時間只允許一個線程訪問,其實Fence機制也有點類似synchronized的,它的主要作用也是限制生產者消費者對同一塊buffer的訪問,我們想想如果沒有Fence機制,那麼生產者消費者模型應該這樣:

生產者生產圖形數據,數據完全生產完之後將buffer轉移到BufferQueue,消費者從BufferQueue獲取buffer,將buffer給到SurfaceFlinger合成,完全使用完畢之後將buffer再放入BufferQueue,生產者又開始申請buffer…如此循環(這種模型會將buffer的擁有權/使用權一併轉移,意味着誰擁有誰纔可以使用)。

這種模型對於只依靠CPU工作的繪製過程是可用的,例如上層的2Dcanvas繪圖,即使用ViewonDraw方法裏面的drawXXX,使用這種繪製方法Fence的fd就爲-1,代表不需要Fence,所以純CPU繪製是不需要同步機制的,反正都是它自己一個人工作,什麼時候生產完,什麼時候消費完都是知道的,但目前大多數的繪製方法都是採用3Dopengl繪圖,使用的GPU,而CPU和GPU的工作是異步的,CPU甚至都無法知道GPU何時工作完成,這種情況如果等生產者完全生產完圖形數據或者消費者完全消費完buffer(完成生產完意味這CPU,GPU都完成各自的工作)再將buffer轉移至BufferQueue效率會非常低,而且如果GPU繪製耗時會使CPU一直等待GPU的完成,此時CPU也不能做其他事情了。還有一點如果按上面模型,buffer在轉移過程中是不會有人使用的,理想情況應該如下:
在這裏插入圖片描述
參考博客:Android中的GraphicBuffer同步機制-Fence

上圖情況表明了buffer一直在被使用,完成生產之後裏面消費,消費完之後立馬生產,所以引入了Fence機制,Fence機制核心其實是等待/喚醒。

每一個buffer都一個Fence狀態,代表這塊buffer是否還在被上一個使用者使用完,並且在轉移時都會攜帶當前Fence的fd,然後可以調用Fence的wait或者waitForever查詢Fence狀態,如果還有人在使用則等待,否則就可以使用。Fence按作用大體分兩種:acquireFencereleaseFence。前者用於生產者通知消費者生產已完成,後者用於消費者通知生產者消費已完成。

例如:
我們通過dequeueBuffer函數申請一塊buffer之後,使用opengl繪製,當調用一系列gl命令,CPU完成了命令執行返回之後將此buffer轉移到BufferQueue,並通過回調函數onFrameAvailable通知消費者,但此時消費者並不能真正拿buffer去合成,因爲有可能GPU還在使用buffer,需要等待一個acquireFence,由GPU發出,只有acquireFence才能代表buffer完全生產完。

反過來,當消費者拿到buffer進行合成之後會經過一系列調用將buffer轉移回BufferQueue,此時如果通過dequeueBuffer函數申請的剛好是這塊剛剛消費完的buffer,那麼同樣需要等待releaseFence表明這快buffer完全使用完畢。

Fence機制有效的處理了CPU和GPU的同步問題,通過分離buffer的擁有權和使用權提高了buffer處理效率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章