レイヤとディスプレイは、合成処理と、ディスプレイ ハードウェアとのインタラクションを表す 2 つのプリミティブです。
レイヤ
レイヤは合成の最も重要なユニットであり、サーフェスと SurfaceControl
のインスタンスを組み合わせたものです。各レイヤには、他のレイヤとの連携を定義する一連のプロパティがあります。以下の表でレイヤのプロパティについて説明します。
プロパティ | 説明 |
---|---|
位置 | ディスプレイ上でレイヤが表示される場所を定義します。レイヤの角の位置や、他のレイヤに対する Z オーダー(他のレイヤの前に配置されるか後に配置されるか)などの情報が含まれます。 |
コンテンツ | 位置プロパティで定義された境界内にレイヤ上のコンテンツをどのように表示するかを定義します。切り抜き(コンテンツの一部を展開してレイヤの境界を埋める)や変形(回転または反転したコンテンツを表示する)などの情報が含まれます。 |
合成 | レイヤを他のレイヤと合成する方法を定義します。ブレンドモードや、アルファ合成のレイヤ全体のアルファ値などの情報が含まれます。 |
最適化 | レイヤを正しく合成するうえで厳密に必要な情報ではないものの、Hardware Composer(HWC)デバイスによる合成方法を最適化するために使用できる情報を提供します。レイヤの表示領域や、前のフレームから更新された部分などの情報が含まれます。 |
ディスプレイ
ディスプレイは、合成のもう 1 つの重要なユニットです。システムで複数のディスプレイを保持でき、通常のシステム オペレーション中にディスプレイを追加または削除することができます。ディスプレイは、HWC のリクエストまたはフレームワークのリクエストに応じて追加または削除されます。HWC デバイスは、外部ディスプレイをデバイスに接続したり接続を解除したりする(ホットプラグ)ときに、ディスプレイの追加または削除をリクエストします。クライアントは、コンテンツが物理ディスプレイではなくオフスクリーン バッファにレンダリングされる仮想ディスプレイをリクエストします。
仮想ディスプレイ
SurfaceFlinger は、内部ディスプレイ(スマートフォンまたはタブレットに組み込まれている)、外部ディスプレイ(HDMI で接続されたテレビなど)、1 つ以上の仮想ディスプレイ(合成された出力をシステム内で使用可能にする)に対応しています。仮想ディスプレイを使用して、画面を録画したり、ネットワーク経由で画面を送信したりできます。仮想ディスプレイ用に生成されたフレームは、BufferQueue に書き込まれます。
仮想ディスプレイでは、メイン ディスプレイと同じレイヤセットを共有する(レイヤスタック)ことも、独自のレイヤセットを使用することもできます。仮想ディスプレイには VSYNC がないため、内部ディスプレイ用の VSYNC によってすべてのディスプレイの合成がトリガーされます。
仮想ディスプレイ対応の HWC 実装では、OpenGL ES(GLES)、HWC、または GLES と HWC の両方で仮想ディスプレイを合成できます。非対応の実装では、仮想ディスプレイは常に GLES を使用して合成されます。
ケーススタディ: screenrecord
screenrecord
コマンドを使用すると、画面に表示されたすべての内容をディスク上の .mp4
ファイルとして録画できます。この場合、システムは SurfaceFlinger から合成フレームを受け取って動画エンコーダに書き込み、エンコードされた動画データをファイルに書き込みます。動画コーデックは別のプロセス(mediaserver
)で管理されるため、大きなグラフィック バッファはシステム中を移動する必要があります。さらに困難なのは、60 fps の動画をフル解像度で録画することです。この作業を効率的に行うための鍵は、BufferQueue です。
MediaCodec
クラスを使用すると、アプリがバッファまたはサーフェスで生のバイトとしてデータを提供できます。screenrecord
によって動画エンコーダへのアクセスがリクエストされると、mediaserver
プロセスは BufferQueue を作成して自身をコンシューマ側に接続し、プロデューサー側をサーフェスとして screenrecord
に渡します。
次に screenrecord
ユーティリティは、メイン ディスプレイをミラーリングする(同じレイヤをすべて保持する)仮想ディスプレイの作成を SurfaceFlinger に要求し、出力を mediaserver
プロセスから渡されたサーフェスに送信するように指示します。この場合、SurfaceFlinger はバッファのコンシューマではなくプロデューサーです。
設定の完了後は、エンコードされたデータが表示されたときに screenrecord
がトリガーされます。アプリが描画すると、バッファが SurfaceFlinger に移動して 1 つのバッファに合成され、mediaserver
プロセスの動画エンコーダに直接送信されます。screenrecord
プロセスではフルフレームは表示されません。mediaserver
プロセスには、内部でバッファを移動し、さらにハンドルによってデータを渡してオーバーヘッドを最小限に抑える独自の方法が備わっています。
ケーススタディ: セカンダリ ディスプレイのシミュレート
WindowManager は、SurfaceFlinger が BufferQueue コンシューマとして機能する可視レイヤの作成を SurfaceFlinger に要求できます。また、SurfaceFlinger が BufferQueue プロデューサーとして機能する仮想ディスプレイの作成を SurfaceFlinger に要求することもできます。
仮想ディスプレイを可視レイヤに接続すると、クローズド ループが作成され、合成された画面がウィンドウに表示されます。このウィンドウが合成出力の一部になるため、次の更新でウィンドウ内の合成画像にもウィンドウ コンテンツが表示されます。実際にこの動作を確認するには、[設定] で [開発者向けオプション] を有効化し、[2 次画面シミュレート] を選択してウィンドウを有効にします。セカンダリ ディスプレイの動作を確認するには、screenrecord
を使用してディスプレイを有効にする動作をキャプチャしてから、フレームごとに再生します。