硬體合成器 (HWC) HAL 會合成從 SurfaceFlinger 收到的圖層,減少合成 OpenGL ES (GLES) 的數量,以及 GPU 執行的作業。
HWC 會將疊加層和 2D Blitter 等物件抽象化為合成表面,並與專用視窗合成硬體通訊,以合成視窗。使用 HWC 合成視窗,而不是讓 SurfaceFlinger 使用 GPU 合成視窗。大多數 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 事件時通知 SurfaceFlinger。
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 會建立控制代碼並合成螢幕。
顯示組合作業
如果 SurfaceFlinger 有要合成的新內容,就會在每次 VSync 時喚醒。這類新內容可以是來自應用程式的新圖片緩衝區,也可以是一或多個圖層的屬性變更。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 會將部分圖層合成為影格緩衝區,而 HWC 會合成影格緩衝區和其餘圖層,並直接寫入輸出緩衝區。
- HWC:HWC 會合成所有圖層,並直接寫入輸出緩衝區。
輸出格式
虛擬螢幕緩衝區輸出格式取決於模式:
- GLES 模式:EGL 驅動程式會在
dequeueBuffer()
中設定輸出緩衝區格式,通常為RGBA_8888
。 消費者必須能夠接受驅動程式設定的輸出格式,否則無法讀取緩衝區。 - MIXED 和 HWC 模式:如果消費者需要存取 CPU,消費者會設定格式。否則格式為
IMPLEMENTATION_DEFINED
,Gralloc 會根據使用情形標記設定最佳格式。舉例來說,如果消費者是視訊編碼器,且 HWC 可以有效率地寫入格式,Gralloc 就會設定 YCbCr 格式。
同步處理柵欄
同步圍欄是 Android 圖形系統的重要環節。柵欄可讓 CPU 工作獨立於並行 GPU 工作進行,只有在存在實際依附元件時才會封鎖。
舉例來說,當應用程式提交 GPU 上產生的緩衝區時,也會提交同步圍欄物件。這個柵欄會發出信號,表示 GPU 已完成寫入緩衝區。
HWC 會要求 GPU 先完成緩衝區寫入作業,再顯示緩衝區。同步圍欄會透過緩衝區和信號傳遞至圖形管線,並在寫入緩衝區時傳遞。顯示緩衝區前,HWC 會檢查同步圍欄是否已發出信號,如果已發出信號,就會顯示緩衝區。
如要進一步瞭解同步圍欄,請參閱「硬體 Compositor 整合」。