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 を使用するには、 gfx
、 view
、および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」を参照してください。