BufferQueue と Gralloc

BufferQueue クラスは、グラフィック データのバッファを生成するコンポーネント (プロデューサー) を、表示またはさらなる処理のためにデータを受け入れるコンポーネント (コンシューマー) に接続します。システム内でグラフィック データのバッファを移動するほぼすべてのものは BufferQueue に依存します。

Gralloc メモリ アロケーターはバッファ割り当てを実行し、2 つのベンダー固有の HIDL インターフェイスを通じて実装されます ( hardware/interfaces/graphics/allocator/およびhardware/interfaces/graphics/mapper/を参照)。 allocate()関数は、予期される引数 (幅、高さ、ピクセル形式) と一連の使用フラグを受け取ります。

BufferQueue のプロデューサーとコンシューマー

コンシューマは BufferQueue データ構造を作成して所有し、プロデューサとは異なるプロセスに存在できます。プロデューサはバッファが必要な場合、 dequeueBuffer()を呼び出して、バッファの幅、高さ、ピクセル形式、および使用フラグを指定することにより、BufferQueue から空きバッファを要求します。次に、プロデューサーはバッファにデータを設定し、 queueBuffer()を呼び出してバッファをキューに返します。次に、コンシューマはacquireBuffer()でバッファを取得し、バッファの内容を利用します。コンシューマが完了すると、 releaseBuffer()を呼び出してバッファをキューに返します。同期フレームワークは、 Android グラフィックス パイプライン内でバッファーがどのように移動するかを制御します。

BufferQueue の一部の特性 (保持できるバッファーの最大数など) は、プロデューサーとコンシューマーによって共同で決定されます。ただし、BufferQueue は必要に応じてバッファを割り当てます。特性が変化しない限り、バッファは保持されます。たとえば、プロデューサーが異なるサイズのバッファを要求した場合、古いバッファは解放され、要求に応じて新しいバッファが割り当てられます。

大量のデータを移動させるのは非効率であるため、バッファの内容は BufferQueue によってコピーされることはありません。代わりに、バッファは常にハンドルによって渡されます。

Systrace を使用して BufferQueue を追跡する

グラフィックス バッファーがどのように移動するかを理解するには、短期間のデバイス アクティビティを記録するツールであるSystraceを使用します。システム レベルのグラフィックス コードは、関連するアプリ フレームワーク コードの多くと同様に、適切に実装されています。

Systrace を使用するには、 gfxview 、およびschedタグを有効にします。 BufferQueue オブジェクトがトレースに表示されます。たとえば、 Grafika のビデオ再生 (SurfaceView) の実行中にトレースを取得すると、 SurfaceViewというラベルの行から、特定の時点でキューに入れられていたバッファの数がわかります。

アプリがアクティブである間、値は増加し、MediaCodec デコーダーによるフレームのレンダリングがトリガーされます。 SurfaceFlinger が動作してバッファを消費している間、値は減少します。ビデオを 30 fps で表示する場合、~60 fps の表示はソースに追いつくことができるため、キューの値は 0 から 1 まで変化します。 SurfaceFlinger は、1 秒あたり 60 回ではなく、実行すべき作業がある場合にのみ起動します。画面が更新されていない場合、システムは作業を回避しようとし、VSYNC を無効にします。

Grafika の Play ビデオ (TextureView)に切り替えて新しいトレースを取得すると、 com.android.grafika / com.android.grafika.PlayMovieActivityというラベルの行が表示されます。これはメイン UI レイヤーであり、別の BufferQueue です。 TextureView は別個のレイヤーではなく UI レイヤーにレンダリングするため、ビデオ主導の更新はすべてここに表示されます。

グラロック

Gralloc アロケータ HAL hardware/libhardware/include/hardware/gralloc.h使用フラグを通じてバッファ割り当てを実行します。使用状況フラグには次のような属性が含まれます。

  • ソフトウェア (CPU) からメモリにアクセスする頻度
  • ハードウェア (GPU) からメモリにアクセスする頻度
  • メモリを OpenGL ES (GLES) テクスチャとして使用するかどうか
  • メモリをビデオ エンコーダで使用するかどうか

たとえば、プロデューサーのバッファー形式がRGBA_8888ピクセルを指定し、プロデューサーがバッファーがソフトウェアからアクセスされる (つまり、アプリが CPU 上のピクセルにアクセスする) ことを示している場合、Gralloc は RGBA 順序でピクセルあたり 4 バイトのバッファーを作成します。代わりに、プロデューサーがそのバッファがハードウェアおよび GLES テクスチャとしてのみアクセスされるように指定した場合、Gralloc は、BGRA の順序付け、非線形のスウィズル レイアウト、代替カラー フォーマットなど、GLES ドライバーが必要とするすべてのことを行うことができます。ハードウェアが優先フォーマットを使用できるようにすると、パフォーマンスが向上します。

一部の値は、特定のプラットフォームでは組み合わせることができません。たとえば、ビデオ エンコーダ フラグには YUV ピクセルが必要な場合があるため、ソフトウェア アクセスを追加してRGBA_8888を指定すると失敗します。

Gralloc によって返されたハンドルは、Binder を介してプロセス間で渡すことができます。

保護されたバッファ

Gralloc 使用フラグGRALLOC_USAGE_PROTECTED使用すると、ハードウェアで保護されたパス経由でのみグラフィックス バッファーを表示できます。これらのオーバーレイ プレーンは、DRM コンテンツを表示する唯一の方法です (DRM で保護されたバッファーには、SurfaceFlinger または OpenGL ES ドライバーはアクセスできません)。

DRM で保護されたビデオは、オーバーレイ プレーンでのみ表示できます。保護されたコンテンツをサポートするビデオ プレーヤーは、SurfaceView で実装する必要があります。保護されていないハードウェア上で実行されているソフトウェアは、バッファの読み取りまたは書き込みを行うことができません。ハードウェアで保護されたパスは、Hardware Composer オーバーレイに表示される必要があります (つまり、Hardware Composer が OpenGL ES コンポジションに切り替わると、保護されたビデオがディスプレイから消えます)。

保護されたコンテンツの詳細については、 「DRM」を参照してください。