實作硬體 Composer HAL

硬體合成器 (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 事件時通知 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 要求函式指標來載入。舉例來說,函式 createLayerHWC2_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. 鎖住新的圖形緩衝區 (如有)。
  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 緩衝區,而非螢幕。硬體合成器 (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 整合」。