BufferQueue 和 gralloc
理解 Android 圖形系統,我們從場景背后的 BufferQueue 和 gralloc HAL 開始。
BufferQueue 類是 Android 中所有圖形的核心。它的角色很簡單:連接產生圖形數據緩沖區的東西(生產者)和接受數據來顯示或進一步處理的東西(消費者)。幾乎所有在系統中移動圖形數據緩沖區的東西都依賴于 BufferQueue。
gralloc 內存分配器執行緩沖區分配,且通過一個供應商特有的 HAL 接口(參考 hardware/libhardware/include/hardware/gralloc.h)實現。alloc() 期待接收的參數為 (width, height, pixel format) 及一系列使用標記(下面詳述)。
BufferQueue 生產者和消費者
基本的用法很直接:生產者請求一塊空閑的緩沖區 (dequeueBuffer()),指定一系列特性,包括寬度,高度,像素格式,和使用標記。生產者填充緩沖區,并將它返回給隊列 (queueBuffer())。隨后,消費者獲得緩沖區(acquireBuffer()) 并使用緩沖區的內容。當消費者完成時,它將緩沖區返回給隊列(releaseBuffer())。
最近 Android 設備支持 同步框架,這使得系統可以與能夠異步處理圖形數據的硬件組件結合使用。比如,生產者可以提交一系列 OpenGL ES 繪制命令,然后在渲染完成之前加入輸出緩沖區隊列。緩沖區伴隨著內容準備就緒時發出信號的柵欄。當緩沖區返回到空閑列表時,第二個柵欄隨附緩沖區,因此消費者可以釋放緩沖區,同時內容仍在使用中。當緩沖區移動通過系統時,這種方法可以提升延遲和吞吐量。
隊列的一些特性,比如它可以持有的最大緩沖區數量,由生產者和消費者聯合決定。然而,BufferQueue 負責根據需要分配緩沖區。除非特性改變,否則緩沖區將保留;比如,如果生產者請求了一個大小不同的緩沖區,老的緩沖區將釋放,新的緩沖區將根據需要分配。
生產者和消費者可以位于不同的進程中。當前,消費者總是創建并擁有數據結構。在更老的版本中,只有生產者一端是 binder 化的 (比如生產者可以在一個遠程進程中,但消費者必須位于隊列創建的進程中)。Android 4.4 及之后的發行版采用了一個更加通用的實現。
BufferQueue 從來不拷貝緩沖區的內容 (像那樣移動大量數據將是非常低效的)。相反,緩沖區總是通過句柄傳遞。
gralloc HAL 使用標記
gralloc 分配器不僅僅是另外一種在本地堆上分配內存的方式;在某些情形下,分配的內存可能不是高速緩存一致的,或者可能完全不能從用戶空間訪問。分配的性質由使用標記決定,這包括這樣的一些屬性:
- 從軟件訪問內存的頻率有多高 (CPU)
- 從硬件訪問內存的頻率有多高 (GPU)
- 內存是否會被用作 OpenGL ES (GLES) 紋理
- 內存是否會被視頻編碼器使用
比如,如果你的格式指定 RGBA 8888 像素,然后你指出緩沖區將從軟件訪問 (意味著你的應用將直接接觸像素),然后分配器必須一個緩沖區,其中每像素 4 個字節,且以 R-G-B-A 的順序。相反,如果你說緩沖區將只從硬件訪問,并作為一個 GLES 紋理,分配器可以做任何 GLES 驅動想要的事情 - BGRA 順序,非線性布局,替代顏色格式,等等。允許硬件使用它喜歡的格式可以提升性能。
一些值在某一平臺上無法結合。比如,視頻編碼器標記可以請求 YUV 像素,于是添加軟件訪問和指定 RGBA 8888 將失敗。
gralloc 分配器返回的句柄可以通過 Binder 在進程之間傳遞。
使用systrace跟蹤BufferQueue
要真正理解圖形緩沖區如何移動,則使用 systrace。系統級的圖形代碼可以很好地進行探索,就像許多相關的應用程序框架代碼一樣。如何高效使用 systrace 的完整描述將需要一篇相當長的文檔。首先啟用 gfx,view 和 sched 標簽。你也將在 trace 中看到 BufferQueues。如果你之前已經在使用 systrace 了,你可能已經看到過它們但可能不確定它們是什么。舉個例子,如果你在 Grafika's "Play video (SurfaceView)" 運行時獲取 trace,標簽為 SurfaceView 的行告訴你在任何給定時刻有多少緩沖區被加入隊列。
值在應用活躍時增加 - MediaCodec 解碼器觸發幀的渲染 - 而在 SurfaceFlinger 工作,消費緩沖區時減小。當視頻的幀率為 30 fps 時,隊列的值將在 0 到 1 之間變動,因為 ~60 fps 顯示可以輕松地跟蹤源。(還要注意 SurfaceFlinger 只有在有工作要做時才喚醒,而不是美妙 60 次。系統努力試圖避免工作,并且如果沒有東西更新屏幕的話完全禁用 VSYNC。)
如果你切換到 Grafika's "Play video (TextureView)" 并獲取一個 trace,你將看到標簽為 com.android.grafika/com.android.grafika.PlayMovieActivity 的行。這是主 UI 層,它只是另一個 BufferQueue。由于 TextureView 渲染到 UI 層 (而不是一個分離的層),你將在這里看到所有的視頻驅動的更新。
關于 systrace 工具的更多信息,請參考 Systrace documentation。
原文
總結
以上是生活随笔為你收集整理的BufferQueue 和 gralloc的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 图形架构
- 下一篇: QEMU 构建系统架构