Android で Vulkan を使ってみる
Vulkan は、Android のメインの低レベル グラフィック API です。独自のゲームエンジンとレンダラを実装するゲームに最適なパフォーマンスを提供します。
ゲームエンジンに Vulkan を実装するために必要なことは、以下のとおりです。
- Vulkan を使用できる Android デバイスを特定する
- 古い Android デバイスをサポートする場合の長所と短所を把握する
- Android ビルド ターゲットに Vulkan を追加する
- Vulkan 用の SPIR-V を作成するシェーダー コンパイラを選択する
- 実行時に利用可能な Vulkan API バージョンを確認する
- Vulkan のプロファイル、フレーム ペーシング、事前回転で Vulkan のレンダリング操作を最適化する方法を学ぶ
- デバッグやパフォーマンス分析用のグラフィックス ツールを選択する
- 注: Unity または Unreal のゲームエンジンとともに Android で Vulkan を使用する方法について詳しくは、以下をご覧ください。
- Unity の Vulkan
- Unreal の Vulkan
Vulkan の最小デバイス仕様を選択する
Vulkan は Android 7.0(API レベル 24)以降の Android で利用できます。ただし、Android 7.0 以降を搭載するすべての Android デバイスが Vulkan をサポートしているわけではありません。どの Vulkan 対応の Android デバイスをゲームでサポートするかを決める必要があります。
推奨事項
以下の仕様を Vulkan サポートの最小要件として使用します。
- デバイスに Android 10.0(API レベル 29)以降が搭載されている
- デバイスが Vulkan API バージョン 1.1 以降をサポートしている
- デバイスに 2022 Android ベースライン プロファイルと互換性のあるハードウェア機能がある
古いデバイスのサポート
グラフィック機能のレベルが異なる幅広いデバイスで実行するよう作られたゲームの場合は、上記の「Vulkan の最小デバイス仕様を選択する」で推奨されているデバイスよりも古いデバイスをサポートすることが必要になることがあります。古いデバイスのサポートを構築する前に、Vulkan がゲームにメリットをもたらすかどうかを評価してください。描画呼び出しが多く、OpenGL ES を使用するゲームでは、OpenGL ES 内での描画呼び出しのコストが高いため、ドライバのオーバーヘッドが著しく増加する可能性があります。これらのゲームは、フレーム時間の大半をグラフィックス ドライバに費やすため、CPU バウンドになる可能性があります。また、OpenGL ES から Vulkan に切り替えると CPU と電力の使用を大幅に削減できる可能性もあります。これは、描画呼び出しを削減するためにインスタンス化を効率よく使用できない複雑なシーンがゲームにある場合に特に当てはまります。古いデバイスをターゲットにする場合は、OpenGL ES のレンダリング サポートをフォールバックとして組み込みます。これは、ターゲット デバイス リスト内の一部のデバイスは、ゲームを確実に実行できない Vulkan 実装を採用している可能性があるためです。
古い Vulkan 対応デバイスは、パフォーマンスや機能が不足していたり、安定性に問題があったりするため、サポートできない場合もあります。
パフォーマンスと機能
古い Vulkan 対応 Android デバイスは、ゲームの実行に必要な機能でレンダリングのパフォーマンスやハードウェアのサポートが欠落している可能性があります。特に、ゲームに高忠実度のグラフィックスがあり、Vulkan が Android でターゲットにしている唯一の API である場合、この可能性が高くなります。多くの古いデバイスでは Vulkan API のバージョンが 1.0.3 に制限され、一般に、最新のハードウェアで利用可能な幅広く使用されている Vulkan 拡張機能がありません。
安定性
古い Android デバイスは、古い Vulkan ドライバを使用している可能性があります。これらのドライバ バージョンには、ゲームの安定性に影響する可能性のあるバグがある恐れがあります。ドライバのバグの回避には、テストとエンジニアリングに多大な時間がかかる可能性があります。
プロジェクトに Vulkan を追加する
プロジェクトに Vulkan を追加するために必要な作業は以下のとおりです。
- Vulkan API ヘッダーを含める
- SPIR-V にシェーダー コードをコンパイルする
- 実行時に Vulkan API を呼び出す
Vulkan API ヘッダーを含める
ゲームで Vulkan を使用するコードをコンパイルするには、Vulkan API ヘッダー ファイルを含める必要があります。Vulkan ヘッダーは Android NDK または Vulkan SDK リリースにあります。NDK の各バージョンには、その NDK のリリース時に利用可能な Vulkan ヘッダーのみが含まれています。NDK にある Vulkan ヘッダーを使用する場合は、Vulkan バージョン 1.3 をサポートするヘッダー ファイルが含まれている NDK バージョン 25 以降を使用してください。Vulkan SDK には最新バージョンのヘッダーが含まれています。
SPIR-V にシェーダー コードをコンパイルする
Vulkan API は、シェーダー プログラムを SPIR-V バイナリ中間形式で提供することを前提とします。この規則は OpenGL ES とは異なります。OpenGL ES では、OpenGL シェーディング言語(GLSL)で記述されたソースコードをテキスト文字列として送信できます。GLSL や上位レベル シェーダー言語(HLSL)などのシェーダー言語で記述されたコードを取得して、Vulkan で使用できるよう SPIR-V モジュールにコンパイルするには、シェーダー コンパイラを使用します。
GLSL で記述されたシェーダー プログラムを SPIR-V にコンパイルするには、shaderc コンパイラを使用します。ゲームで HLSL を使用している場合は、DirectXShaderCompiler が SPIR-V 出力をサポートします。一般に、ゲームのアセット ビルドプロセスの一部としてオフラインでシェーダー プログラムをコンパイルし、ランタイム アセットの一部として SPIR-V モジュールを含めます。
実行時に Vulkan API を呼び出す
Vulkan API を呼び出すには、ゲームで Vulkan API 呼び出しへの関数ポインタを取得する必要があります。このための最も簡単な方法は、libvulkan.so
共有ライブラリにリンクすることです。このライブラリは Android NDK に含まれています。ライブラリへのリンクには短所が 2 つあります。1 つは関数ディスパッチのオーバーヘッドが増えること、もう 1 つは Vulkan API の関数ポインタの自動的な解決に制限が生じることです。
Vulkan API 関数を呼び出すと、Vulkan ローダと呼ばれるコンストラクトで管理されるディスパッチ テーブルに制御が渡されます。Android は独自の Vulkan ローダ実装を使用し、LunarG ローダは使用しません。このローダシステムは、Vulkan API のレイヤ アーキテクチャの一部です。ビルド時にシステム ライブラリにリンクすると、API 呼び出しのディスパッチ レベルが増えます。オーバーヘッドはわずかですが、大量の Vulkan 呼び出しを実行するゲームでは目立つ可能性があります。
通常、システム ライブラリが解決するのは、コア API の一部と見なされる Vulkan 関数へのポインタのみです。Vulkan には多くの拡張機能があり、定義される Vulkan 関数も増えますが、その多くはシステム ライブラリで自動的には解決されません。これらの Vulkan 関数を使用するには、事前にそのポインタを手動で解決する必要があります。
これらの問題を軽減するには、実行時に使用する予定があるすべての Vulkan 関数へのポインタを動的に解決します。これを実現する 1 つの方法は、volk などのオープンソースのメタローダ ライブラリを使用することです。サンプルゲーム AGDKTunnel は、このために volk を統合しています。メタローダ ライブラリを使用する場合は、ビルド スクリプトで libvulkan.so
共有ライブラリにリンクしないでください。
利用可能な Vulkan API バージョンを確認する
Android がサポートする Vulkan API のバージョンは以下のとおりです。
- 1.0.3
- 1.1
- 1.3
デバイスで使用可能な Vulkan API の最も高いバージョン番号は、Android のバージョンと Vulkan ドライバのサポートによって決まります。
Android バージョン
プラットフォームでの Vulkan API バージョンのサポートは、Android の最小バージョン(API レベル)によって異なります。
- 1.3 - Android 13.0(API レベル 33)以降
- 1.1 - Android 10.0(API レベル 29)以降
- 1.0.3 - Android 7.0(API レベル 24)以降
Vulkan ドライバのサポート
Android プラットフォームでサポートされる Vulkan API バージョンでも、デバイスの Vulkan ドライバでサポートされるとは限りません。Android 13 を搭載したデバイスが、Vulkan API のバージョン 1.1 しかサポートしていないこともあります。
Vulkan を初期化する際は、以下のバージョンより上位の API バージョンをリクエストしないでください。
- デバイスに搭載された Android のバージョンに対する Vulkan API の最大バージョン
- vkEnumerateInstanceVersion によって報告された Vulkan API バージョン
- VkPhysicalDeviceProperties 構造体の
apiVersion
プロパティで報告された Vulkan API バージョン
以下に、サポートされる Vulkan API の最も高いバージョンを判断する例を示します。
// Minimum Android API levels for Vulkan 1.3/1.1 version support
static constexpr int kMinimum_vk13_api_level = 33;
static constexpr int kMinimum_vk11_api_level = 29;
uint32_t GetHighestSupportedVulkanVersion(VkPhysicalDevice physical_device) {
uint32_t instance_api_version = 0;
vkEnumerateInstanceVersion(&instance_api_version);
VkPhysicalDeviceProperties device_properties;
vkGetPhysicalDeviceProperties(physical_device, &device_properties);
// Instance and device versions don't have to match, use the lowest version
// number for API support if they don't.
const uint32_t driver_api_version =
(instance_api_version < device_properties.apiVersion) ?
instance_api_version : device_properties.apiVersion;
const int device_api_level = android_get_device_api_level();
if (device_api_level >= kMinimum_vk13_api_level &&
driver_api_version >= VK_API_VERSION_1_3) {
return VK_API_VERSION_1_3;
} else if (device_api_level >= kMinimum_vk11_api_level &&
driver_api_version >= VK_API_VERSION_1_1) {
return VK_API_VERSION_1_1;
}
return VK_API_VERSION_1_0;
}
Vulkan プロファイルの互換性を判断する
Vulkan プロファイルは、Vulkan デバイスがプロファイルとの互換性を維持するためにサポートする必要がある一連の必須機能、拡張機能、機能、最小パラメータ制限を定義する、JSON 形式のファイルです。デバイスが特定の Vulkan プロファイル(2022 Android ベースライン プロファイルなど)と互換性があるかどうかは、オープンソースの Vulkan Profiles API ライブラリを使用して判断できます。また、プロファイルの JSON ファイルを自分で解析し、関連する Vulkan API を使用しているデバイスの機能をクエリして、プロファイルの互換性を判断することもできます。
Vulkan プロファイル
Android では Vulkan プロファイルを使用しています。これは、Android を搭載した各デバイスで使用できる機能と拡張機能を定義します。
Android ベースライン プロファイル(ABP)は、Vulkan プロファイルの作成を初めて試みたものです。ABP2021 と ABP2022 は、当時のアクティブ デバイスの 85% 以上をカバーすることを目的とした過去志向のプロファイルです。今後、新しい ABP は作成されません。
Android 向け Vulkan プロファイル(VPA)は、ソフトウェア デベロッパーのニーズを反映し、ハードウェア デベロッパーが提供できる限り早く一貫した機能を推進することを目的とした、新しい先進的なプロファイルです。VPA15_minimums は Android 15 の最初のプロファイルです。Android のメジャー リリースごとに、新しい VPA が毎年リリースされます。
フレーム ペーシングを実装する
質の高いゲームプレイ エクスペリエンスを提供するには、適切なフレーム ペーシングが不可欠です。Android Game Development Kit には、ゲームで最適なフレーム ペーシングを実現するための Frame Pacing ライブラリが含まれています。実装について詳しくは、Android Frame Pacing を Vulkan レンダラに統合するをご覧ください。
事前回転を実装する
Android デバイスは複数の向きで表示できます。デバイスの向きは、レンダリング サーフェスの向きと異なる場合があります。Android の OpenGL ES と異なり、Vulkan はこの 2 つの差を処理しません。画面の向きのプロセスの仕組みと、Vulkan を使用する際に画面の向きの差を処理する最適な方法については、Vulkan の事前回転でデバイスの向きを処理するをご覧ください。
Vulkan レンダリングのトラブルシューティングとプロファイリングを行う
レンダリングに関する問題と、Vulkan レンダリング コードに関するパフォーマンスの問題の診断に役立つ複数のツールがあります。
Vulkan のデバッグ ツールとプロファイリング ツールの詳細については、ツールと高度な機能のセクションをご覧ください。
Vulkan 検証レイヤ
Vulkan 検証レイヤはランタイム ライブラリとして、Vulkan API 呼び出しの検査や、間違った使用や最適でない使用に関する警告、エラーの出力に使用できます。検証プロセスによってランタイム オーバーヘッドが増加し、ゲームのパフォーマンスに影響するため、これらの検証レイヤはデフォルトでは有効ではありません。ゲームで検証レイヤを使用する方法については、検証レイヤを使用したデバッグをご覧ください。
フレーム キャプチャ ツール
ゲームフレーム中に行われた Vulkan API 呼び出しを記録して再現するには、フレーム キャプチャ ツールを使用します。これらのツールを使って、以下の操作を行えます。
- 有効なグラフィック リソースに関する情報とその可視化を確認する
- ゲームで行われた API 呼び出しのシーケンスと API パラメータを確認する
- 描画呼び出し時のグラフィックス パイプラインの状態を調べる
- フレーム内の特定の描画呼び出しまでのレンダリングの結果を可視化する
Android で実行中のゲームのフレームをキャプチャするには、オープンソースの RenderDoc ツールを使用します。RenderDoc は、Vulkan と OpenGL ES の両方のフレーム キャプチャをサポートします。
Android GPU Inspector(AGI)を使用して Vulkan のフレームをキャプチャすることもできます。
パフォーマンス分析ツール
フレームレートが最適化されないゲーム内のレンダリングの問題を調べるには、パフォーマンス分析ツールを使用します。個々の GPU ベンダーは、ゲームをプロファイリングし、GPU アーキテクチャに固有のパフォーマンス データを提供することを目的とするツールを提供しています。ゲームのパフォーマンス特性とボトルネックは、ベンダーが異なる GPU でレンダリングする場合や、同じベンダーでも世代が異なる GPU でレンダリングする場合で、大きく変わる可能性があります。
また、Android GPU Inspector を使用して、パフォーマンス データを収集、分析することもできます。ベンダーのツールと異なり、Android GPU Inspector は、さまざまなベンダーの複数の GPU に対応しています。ただし、Android GPU Inspector は古い Android デバイスには対応していません。また、すべての新しいデバイスに対応するとは限りません。
CTS-D で Vulkan テストを改善する
Android 搭載デバイスのメーカーは、互換性テストスイート(CTS)を使用して、デバイスの互換性を確保しています。デベロッパー提供の CTS(CTS-D)は、今後の Android デバイスがユースケースを満たし、バグなくスムーズにアプリを実行できるように、Android アプリ デベロッパーが送信するテストです。
特定の Android デバイスに影響する Vulkan アプリケーションで新しいバグをトリガーできた場合は、問題とその確認方法を説明した新しいテスト案を送信できます。これにより、デバイスの今後のアップデートで問題が修正され、他のデバイスで同じバグが発生しないようにします。
テストプランの提出方法については、CTS 提出手続きをご覧ください。