實現硬件作曲家 HAL

Hardware Composer (HWC) HAL 合成從 SurfaceFlinger 接收的層,減少合成OpenGL ES (GLES)和 GPU 執行的數量。

HWC 將對象(例如疊加層和 2D blitter)抽象為複合表面,並與專門的窗口合成硬件通信以合成窗口。使用 HWC 來合成窗口,而不是讓 SurfaceFlinger 與 GPU 合成。大多數 GPU 沒有針對合成進行優化,當 GPU 從 SurfaceFlinger 合成層時,應用程序無法使用 GPU 進行自己的渲染。

HWC 實現應該支持:

  • 至少四個疊加層:
    • 狀態欄
    • 系統欄
    • 應用程序
    • 壁紙/背景
  • 大於顯示屏的圖層(例如壁紙)
  • 同時預乘每像素 alpha 混合和每平面 alpha 混合
  • 受保護視頻播放的硬件路徑
  • RGBA 打包順序、YUV 格式以及平鋪、混合和跨步屬性

要實施 HWC:

  1. 實現一個不可操作的 HWC 並將所有組合工作發送到 GLES。
  2. 實現一種算法,以增量方式將組合委託給 HWC。例如,僅將前三個或四個表面委託給 HWC 的覆蓋硬件。
  3. 優化 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 名稱引用。幾乎每個函數都是通過使用getFunction提供的hwc2_device_t請求函數指針來加載的。例如,函數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. 鎖存新的圖形緩衝區(如果存在)。
  3. 如果步驟 1 或 2 導致顯示內容髮生更改,則執行新的合成。

為了執行新的合成,SurfaceFlinger 創建和銷毀圖層或修改圖層狀態(如果適用)。它還使用諸如setLayerBuffersetLayerColor之類的調用更新圖層的當前內容。更新所有層後,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 緩衝區而不是屏幕。 Hardware Composer (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 根據使用標誌設置最佳格式。例如,如果消費者是視頻編碼器,Gralloc 會設置 YCbCr 格式,並且 HWC 可以高效地編寫該格式。

同步圍欄

同步(sync)柵欄是 Android 圖形系統的一個重要方面。 Fences 讓 CPU 工作獨立於並發 GPU 工作進行,僅在存在真正依賴時才阻塞。

例如,當應用提交在 GPU 上生成的緩衝區時,它也會提交一個同步圍欄對象。當 GPU 完成寫入緩衝區時,此柵欄會發出信號。

HWC 要求 GPU 在緩衝區顯示之前完成寫入緩衝區。同步圍欄通過帶有緩衝區的圖形管道傳遞,並在寫入緩衝區時發出信號。在顯示緩衝區之前,HWC 檢查同步圍欄是否已發出信號,如果有,則顯示緩衝區。

有關同步圍欄的更多信息,請參閱Hardware Composer 集成