SurfaceFlinger 提供的 Hardware Composer (HWC) HAL 複合層,可降低 OpenGL ES (GLES) 和 GPU 效能。
HWC 會將重疊和 2D blit 等物件抽象化,以便合成介面,並與專門的視窗合成硬體通訊,以便合成視窗。使用 HWC 建立複合視窗,而非讓 GPU 產生 SurfaceFlinger 複合視窗。大多數 GPU 並未針對合成進行最佳化,當 GPU 合成 SurfaceFlinger 的圖層時,應用程式就無法使用 GPU 進行轉譯。
HWC 實作項目應支援下列項目:
- 至少四個疊加層:
- 狀態列
- 系統列
- 應用程式
- 桌布/背景
- 圖層大於螢幕 (例如桌布)
- 同時進行每個像素的預乘 Alpha 混合和每個平面的 Alpha 混合
- 受保護影片播放的硬體路徑
- RGBA 封裝順序、YUV 格式,以及傾斜、旋轉和步長屬性
如何實作 HWC:
- 實作非作業 HWC,並將所有合成工作傳送至 GLES。
- 實作演算法,以便逐步將合成作業委派給 HWC。例如,只將前三或四個途徑委派給 HWC 的重疊硬體。
- 最佳化 HWC。其中可能包括:
- 選取可將 GPU 負載降到最低的途徑,並將其傳送至 HWC。
- 正在偵測螢幕是否正在更新。如果不是,請將合成作業委派給 GLES 而非 HWC,以節省電力。當畫面再次更新時,請繼續將組合卸載至 HWC。
- 準備常見用途,例如:
- 主畫面,包括狀態列、系統列、應用程式視窗和動態桌布
- 在直向和橫向模式下以全螢幕模式顯示遊戲
- 以全螢幕播放影片,搭配隱藏式輔助字幕和播放控制項
- 受保護的影片播放
- 分割畫面多視窗
HWC 原始物件
HWC 提供兩種基本元素:圖層和螢幕,用來代表合成作業及其與顯示硬體的互動情形。HWC 也提供 VSYNC 控制項和 SurfaceFlinger 回呼,以便在 VSYNC 事件發生時通知。
HIDL 介面
Android 8.0 以上版本會使用名為 Composer HAL 的 HIDL 介面,用於 HWC 和 SurfaceFlinger 之間的繫結 IPC。Composer HAL 會取代舊版 hwcomposer2.h
介面。如果廠商提供 HWC 的 Composer HAL 實作,Composer HAL 就能直接接受來自 SurfaceFlinger 的 HIDL 呼叫。如果供應商提供 HWC 的舊版實作項目,Composer HAL 會從 hwcomposer2.h
載入函式指標,並將 HIDL 呼叫轉送至函式指標呼叫。
HWC 提供函式,可用於判斷特定螢幕的屬性;切換不同的螢幕設定 (例如 4k 或 1080p 解析度) 和色彩模式 (例如原生色彩或真實 sRGB);以及開啟/關閉螢幕或進入省電模式 (如有支援)。
函式指標
如果廠商直接實作 Composer HAL,SurfaceFlinger 會透過 HIDL IPC 呼叫其函式。舉例來說,如要建立圖層,SurfaceFlinger 會在 Composer HAL 上呼叫 createLayer()
。
如果供應商實作 hwcomposer2.h
介面,Composer HAL 會呼叫 hwcomposer2.h
函式指標。在 hwcomposer2.h
註解中,HWC 介面函式會以 lowerCamelCase 名稱參照,這些名稱不會在介面中以已命名欄位的形式存在。使用 hwc2_device_t
提供的 getFunction
要求函式指標,即可載入幾乎每個函式。舉例來說,函式 createLayer
是 HWC2_PFN_CREATE_LAYER
類型的函式指標,會在列舉值 HWC2_FUNCTION_CREATE_LAYER
傳遞至 getFunction
時傳回。
如需 Composer HAL 函式和 HWC 函式傳遞函式的詳細說明文件,請參閱 composer
。如需 HWC 函式指標的詳細說明文件,請參閱 hwcomposer2.h
。
圖層和顯示處理程序
圖層和顯示方式是由 HWC 產生的控點操控。這些控制項對 SurfaceFlinger 來說是不可見的。
當 SurfaceFlinger 建立新圖層時,會呼叫 createLayer
,並針對直接實作傳回 Layer
類型,或針對傳送方式實作傳回 hwc2_layer_t
類型。當 SurfaceFlinger 修改該層的屬性時,SurfaceFlinger 會將 hwc2_layer_t
值傳遞至適當的修改函式,並附上進行修改所需的任何其他資訊。hwc2_layer_t
類型足夠大,可容納指標或索引。
實體螢幕是透過熱插拔建立。當實體螢幕接上電源時,HWC 會建立控制代碼,並透過熱插電回呼將控點傳遞至 SurfaceFlinger。虛擬螢幕是由 SurfaceFlinger 呼叫 createVirtualDisplay()
來要求螢幕而建立。如果 HWC 支援虛擬顯示組合,則會傳回句柄。接著,SurfaceFlinger 會將螢幕的組合委派給 HWC。如果 HWC 不支援虛擬螢幕組合,SurfaceFlinger 會建立控制代碼並合成螢幕。
顯示組合作業
每個 VSYNC 一次,如果 SurfaceFlinger 有新內容要合成,就會喚醒。這類新內容可以是應用程式中的新圖片緩衝區,或是一或多個圖層屬性的變更。當 SurfaceFlinger 喚醒時:
- 處理交易 (如有)。
- 鎖定新的圖形緩衝區 (如果有的話)。
- 如果步驟 1 或 2 導致顯示內容變更,就會執行新的組合。
如要執行新的合成作業,SurfaceFlinger 會視情況建立及銷毀圖層或修改圖層狀態。它也會使用 setLayerBuffer
或 setLayerColor
等呼叫,更新包含目前內容的圖層。所有圖層都更新後,SurfaceFlinger 會呼叫 validateDisplay
,並指示 HWC 檢查圖層狀態,並決定合成作業的執行方式。根據預設,SurfaceFlinger 會嘗試設定每個圖層,以便由 HWC 合成圖層;但在某些情況下,SurfaceFlinger 會透過 GPU 備用方案合成圖層。
呼叫 validateDisplay
後,SurfaceFlinger 會呼叫 getChangedCompositionTypes
,查看 HWC 是否希望在執行合成作業前變更任何圖層合成類型。如要接受變更,SurfaceFlinger 會呼叫 acceptDisplayChanges
。
如果任何圖層標示為 SurfaceFlinger 合成,SurfaceFlinger 就會將這些圖層合成至目標緩衝區。接著,SurfaceFlinger 會呼叫 setClientTarget
為螢幕提供緩衝區,以便讓緩衝區顯示在畫面上,或以尚未標記為 SurfaceFlinger 組合的圖層來合併。如果沒有標示要進行 SurfaceFlinger 合成的圖層,SurfaceFlinger 會略過合成步驟。
最後,SurfaceFlinger 會呼叫 presentDisplay
,告知 HWC 完成組合程序並顯示最終結果。
多螢幕
Android 10 支援多個實體螢幕。設計用於 Android 7.0 以上版本的 HWC 實作時,HWC 定義中不會存在以下限制:
- 系統會假設只有一個內部螢幕。內部顯示器是指在啟動期間,初始熱插拔裝置回報的顯示器。內部螢幕熱插後就無法中斷連線。
- 除了內部螢幕之外,在裝置正常運作期間,任何數量的外部螢幕都可以熱插拔。架構會假設第一個內部螢幕之後的所有熱插拔都是外部螢幕,因此如果新增更多內部螢幕,這些螢幕會被錯誤分類為
Display.TYPE_HDMI
,而非Display.TYPE_BUILT_IN
。
雖然上述的 SurfaceFlinger 作業會針對每個螢幕執行,但即使只更新一個螢幕的內容,作業也會依序針對所有有效螢幕執行。
舉例來說,如果外部顯示器更新,序列就會是:
// In Android 9 and lower: // Update state for internal display // Update state for external display validateDisplay(<internal display>) validateDisplay(<external display>) presentDisplay(<internal display>) presentDisplay(<external display>) // In Android 10 and higher: // Update state for internal display // Update state for external display validateInternal(<internal display>) presentInternal(<internal display>) validateExternal(<external display>) presentExternal(<external display>)
虛擬顯示器組合
虛擬螢幕組合與外部螢幕組合類似。虛擬顯示器組合和實體顯示器組合之間的差異在於,虛擬顯示器會將輸出內容傳送至 Gralloc 緩衝區,而非傳送至螢幕。硬體編譯器 (HWC) 會將輸出內容寫入緩衝區、提供完成柵欄,並將緩衝區傳送至消費者 (例如影片編碼器、GPU、CPU 等)。如果顯示管道寫入記憶體,虛擬螢幕可以使用 2D/blitter 或覆蓋。
模式
在 SurfaceFlinger 呼叫 validateDisplay()
HWC 方法後,每個影格都會處於下列三種模式之一:
- GLES:GPU 會將所有圖層合成,並直接寫入輸出緩衝區。HWC 不會參與組合。
- MIXED:GPU 會將部分圖層合併至 framebuffer,HWC 則會合併 framebuffer 和其餘層,並直接寫入輸出緩衝區。
- HWC:HWC 會合成所有圖層,並直接寫入輸出緩衝區。
輸出格式
虛擬顯示器緩衝區輸出格式取決於其模式:
- GLES 模式:EGL 驅動程式會在
dequeueBuffer()
中設定輸出緩衝區格式,通常為RGBA_8888
。取用端必須能夠接受驅動程式集的輸出格式,否則無法讀取緩衝區。 - 混合模式和 HWC 模式:如果消費者需要 CPU 存取權,則消費者會設定格式。否則格式為
IMPLEMENTATION_DEFINED
,而 Gralloc 會根據用法標記設定最佳格式。舉例來說,如果使用者是影片編碼器,且 HWC 可有效地寫入格式,Gralloc 就會設定 YCbCr 格式。
同步處理圍欄
同步 (sync) 圍欄是 Android 圖形系統的重要部分。柵欄可讓 CPU 獨立於並行 GPU 工作進行,只有在存在真正的依附元件時才會阻斷。
舉例來說,當應用程式提交在 GPU 上產生的緩衝區時,也會提交同步化圍欄物件。當 GPU 完成寫入緩衝區時,這個圍欄就會發出信號。
HWC 需要 GPU 完成寫入緩衝區後才會顯示緩衝區。同步化圍籬會在寫入緩衝區時,透過繪圖管線傳遞緩衝區和信號。在顯示緩衝區之前,HWC 會檢查同步區是否已發出信號,如果已發出信號,就會顯示緩衝區。
如要進一步瞭解同步化圍欄,請參閱「硬體音樂製作人整合」。