實施硬體作曲家 HAL

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

HWC 將覆蓋層和 2D 位元區塊傳輸等物件抽象化為複合表面,並與專用視窗複合硬體通訊以複合視窗。使用 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 介面函數由介面中不存在的小駝峰名稱引用為命名欄位。幾乎每個函數都是透過使用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. 鎖存新的圖形緩衝區(如果存在)。
  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/位元塊傳輸或覆蓋。

模式

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格式。

同步圍欄

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

例如,當應用程式提交在 GPU 上產生的緩衝區時,它也會提交同步柵欄物件。當 GPU 完成寫入緩衝區時,此柵欄會發出訊號。

HWC 要求 GPU 在顯示緩衝區之前完成寫入緩衝區。同步柵欄與緩衝區一起通過圖形管道,並在寫入緩衝區時發出訊號。在顯示緩衝區之前,HWC 檢查同步柵欄是否已發出訊號,如果有,則顯示緩衝區。

有關同步柵欄的更多信息,請參閱Hardware Composer 整合