Surface と SurfaceHolder

Surface のオブジェクトを使用することで、アプリは画面上に表示される画像をレンダリングできます。SurfaceHolder インターフェースを使用することで、サーフェスの編集やコントロールが可能になります。

Surface

Surface は、プロデューサーがバッファを消費者と交換するためのインターフェースです。

通常、表示サーフェスの BufferQueue は、トリプル バッファリングに設定されます。バッファはオンデマンドで割り当てられるため、60 fps ディスプレイで 30 fps など、プロデューサーがバッファを緩やかに生成する場合、キューにはバッファが 2 つだけ割り当てられる可能性があります。オンデマンドでバッファを割り当てると、メモリ消費量を最小限に抑えることができます。dumpsys SurfaceFlinger 出力で各レイヤに関連付けられたバッファの概要を確認できます。

ほとんどのクライアントは、OpenGL ES または Vulkan を使用してサーフェスにレンダリングします。ただし、キャンバスを使用してサーフェスにレンダリングするクライアントも存在します。

キャンバスのレンダリング

キャンバスの実装は、Skia Graphics Library が提供しています。長方形を描画する場合は、バッファに適切にバイトを設定する Canvas API を呼び出します。バッファが 2 つのクライアントによって同時に更新、または表示中に書き込みされないようにするには、バッファをロックしてアクセスします。キャンバス ロックで操作するには、次のコマンドを使用します。

  • lockCanvas() は、CPU でレンダリングするバッファをロックし、描画に使用する Canvas を返します。
  • unlockCanvasAndPost() は、バッファをロック解除してコンポジタに送信します。
  • lockHardwareCanvas() は、GPU でレンダリングするバッファをロックし、描画に使用するキャンバスを返します。

プロデューサーが BufferQueue からバッファを初めて要求すると、バッファが割り当てられ、0 に初期化されます。初期化は、プロセス間で誤ってデータを共有しないようにするために必要です。ただし、バッファを再利用すると、以前の内容はそのまま残ります。何も描画することなく lockCanvas()unlockCanvasAndPost() を繰り返し呼び出すと、プロデューサーは以前にレンダリングされたフレーム間を循環します。

サーフェスのロックコードまたはロック解除コードは、以前にレンダリングされたバッファへの参照を保持します。サーフェスをロックするときにダーティな領域を指定すると、直前のバッファからダーティでないピクセルをコピーします。通常、SurfaceFlinger または HWC がバッファを処理します。ただし、バッファからの読み取りのみが必要なため、排他的なアクセスを待つ必要はありません。

SurfaceHolder

SurfaceHolder は、システムがサーフェスの所有権をアプリと共有するために使用するインターフェースです。サーフェスのパラメータを取得および設定する API は SurfaceHolder を介して実装されるため、サーフェスを操作するクライアントには SurfaceHolder が必要な場合があります。SurfaceView には SurfaceHolder が含まれています。

ビューを操作するコンポーネントのほとんどは、SurfaceHolder を使用します。MediaCodec などの他の API は、サーフェス自体で動作します。