RenderScript からの移行

Android 12 以降、RenderScript API のサポートは終了します。この API は引き続き機能しますが、デバイスとコンポーネント メーカーによるハードウェア アクセラレーションのサポートはいずれ終了することが予測されます。GPU のアクセラレーションを最大限に活用できるよう、スクリプトを Vulkan に移行するか、置換ツールキットを使用して組み込み関数から移行することをおすすめします。

Android プラットフォームの RenderScript のサポート終了に伴い、Android Gradle プラグインの RenderScript のサポートも終了します。Android Gradle プラグイン 7.2 以降、RenderScript API のサポートは終了しています。それらの API は引き続き機能しますが、警告がトリガーされ、AGP の将来のバージョンで完全に削除される予定です。このガイドでは、RenderScript からの移行方法について説明します。

組み込み関数からの移行

RenderScript の組み込み関数は RenderScript のサポート終了後も引き続き機能しますが、実行できるのは GPU ではなく CPU に対してのみです。

アプリケーションで組み込み関数を使用する場合、スタンドアロンの代替ライブラリを使用できます。既存の RenderScript CPU 実装を使用するより高速であることがテストで確認されています。

ツールキットには次の関数が含まれています。

  • ブレンド
  • ぼかし
  • カラー マトリックス
  • 積和演算
  • ヒストグラムと histogramDot
  • ルックアップ テーブル(LUT)と LUT 3D
  • サイズ変更
  • YUV から RGB

詳細と制限事項については、ツールキットの README.md ファイルと Toolkit.kt. ファイルをご覧ください。

ライブラリをダウンロード、追加、使用するには、次の手順を実施します。

  1. GitHub からプロジェクトをダウンロードします。

  2. renderscript-toolkit module を見つけてビルドします。

  3. アプリの build.gradle ファイルを変更して、Android Studio プロジェクトにライブラリを追加します。

  4. ツールキットの適切なメソッドを呼び出します。

例: ScriptIntrinsicBlur 関数から移行する

ScriptIntrinsicBlur 関数を置き換える手順は次のとおりです。

  • ビットマップのぼかし処理のために Toolkit.blur を呼び出します。

    var blurredBitmap = Toolkit.blur(myBitmap, radius)
    
  • バイトの配列で表現された画像のぼかし処理では、幅、高さ、ピクセルあたりのバイト数を指定します。

    val outArray = Toolkit.blur(inputArray, bytesPerPixel, width, height, radius)
    

Android 12(API レベル 31)以降を対象としている場合は、Toolkit.blur() ではなく RenderEffect クラスを使用することをおすすめします。

スクリプトからの移行

GPU アクセラレーションを最大限に活用できるよう、RenderScript スクリプトをクロス プラットフォーム Vulkan API に移行することをおすすめします。移行しなくてもスクリプトは引き続き実行されますが、ドライバの対応状況に応じて、GPU ではなく CPU で実行されることがあります。

機能の移行方法を理解するには、サンプルアプリをご覧ください。このサンプルでは、ビットマップのぼかし処理と RenderScript でのカラー マトリックス変換を行う方法と、Vulkan を使用して同等のコードを作成する方法を説明します。

アプリでさまざまなリリースをサポートする必要がある場合は、Android 9(API レベル 28)以前を搭載したデバイスには RenderScript を使用し、Android 10(API レベル 29)以降では Vulkan を使用します。

Vulkan は Kotlin API または Java API を提供していないため、RenderScript から Vulkan へは直接マッピングされません。Kotlin または Java からこのコードにアクセスするには、NDK を使用して Vulkan コードを記述し、JNI 関数を作成する必要があります。

以降のセクションでは、RenderScript からの移行のさまざまな側面について説明します。サンプルアプリでは、これらの考慮事項をほぼすべてカバーしています。これらの考慮事項を理解するには、RenderScript と Vulkan の対応するコードを比較します。

初期化

Kotlin または Java で RenderScript コンテキスト オブジェクトを作成する代わりに、次の手順に沿って NDK を使用して Vulkan コンテキストを作成します。

  1. Vulkan インスタンスを作成します。

  2. コンピューティング キューに対応している Vulkan 物理デバイスを選択します。

  3. Vulkan 論理デバイスを作成し、コンピューティング キューを取得します。

必要に応じて、Android で Vulkan 検証レイヤを設定して、Vulkan アプリの開発を高速化できます。

このサンプルアプリでは、VulkanContext.h で Vulkan コンテキストを初期化する方法を紹介します。 詳しくは、Vulkan 仕様の初期化デバイスとキューのセクションをご覧ください。

割り当て

RenderScript の割り当ては、Vulkan ストレージ イメージまたは Vulkan ストレージ バッファに移行できます。読み取り専用のイメージでパフォーマンスを向上させるには、取得操作でサンプル画像を、イメージ サンプラーの組み合わせとして使用するか、個別のサンプラーサンプル イメージのバインドとともに使用します。

Vulkan リソースは Vulkan 内で割り当てられます。他の Android コンポーネントとやり取りするときにメモリのコピーのオーバーヘッドを回避するには、VK_ANDROID_external_memory_android_hardware_buffer 拡張子を使用して Android を AHardwareBuffer Vulkan にインポートすることを検討してください。この拡張機能は、Vulkan 1.1 をサポートするすべての Android デバイスで利用できます。詳しくは、FEATURE_VULKAN_HARDWARE_VERSION をご覧ください。

このサンプルアプリでは、VulkanResources.h で Vulkan リソースを作成する方法を紹介します。 詳しくは、Vulkan 仕様のリソース作成リソース記述子をご覧ください。

スクリプト

RenderScript スクリプトを Vulkan コンピューティング シェーダーに変換する必要があります。また、RenderScript グローバルの使用方法に応じてコードを調整する必要があります。

Vulkan コンピューティング シェーダーの作成

Vulkan コンピューティング シェーダーは通常、OpenGL シェーディング言語(GLSL)で記述され、 標準ポータブル中間言語(SPIR-V)形式にコンパイルされます。

シェーダーをアプリに追加する方法の詳細と手順については、Android の Vulkan シェーダー コンパイラをご覧ください。

スクリプト グローバルの調整

スクリプト グローバルの特性に基づいて、シェーダー内で変更されていないグローバルには、特殊定数、プッシュ定数、または均一なバッファ オブジェクトを使用することをおすすめします。

  • 特殊定数: カーネルの呼び出し全体で一貫性のあるスクリプト グローバルに推奨されます。特殊定数の値を変更するには、コンピューティング パイプラインを再作成する必要があります。
  • プッシュ定数: 頻繁に変更され、maxPushConstantsSize よりも小さい(最低保証値: 128 バイト)スクリプト グローバルに推奨されます。
  • 均一なバッファ: プッシュ定数の上限よりも大きいサイズのスクリプト グローバルに推奨されます。

シェーダー内で変更されたグローバルについては、Vulkan ストレージ イメージまたは Vulkan ストレージ バッファを使用できます。

計算

GPU がコンピューティング シェーダーを実行できるようにするには、Vulkan コンピューティング パイプラインを作成する必要があります。

Vulkan コンピューティング パイプラインの作成

サンプルアプリの ComputePipeline.h ファイルでは、Vulkan コンピューティング パイプラインを作成する方法を紹介します。

コンパイルされた SPIR-V シェーダーを Vulkan で使用するには、次のように Vulkan コンピューティング パイプラインを構築します。

  1. コンパイル済みの SPIR-V シェーダーでシェーダー モジュールを作成します。
  2. リソース バインドを指定して記述子セットのレイアウトを作成します(詳しくは、割り当てをご覧ください)。
  3. 記述子セット レイアウトから記述子セットを作成します。
  4. 記述子セット レイアウトからパイプライン レイアウトを作成します。
  5. シェーダー モジュールとパイプライン レイアウトを使用してコンピューティング パイプラインを作成します。

詳しくは、Vulkan 仕様の コンピューティング パイプラインのセクションをご覧ください。

計算の開始

コンピューティング パイプラインを使用して計算を開始する手順は、次のとおりです。

  1. Vulkan リソースを使用して記述子セットを更新します。
  2. Vulkan コマンド バッファを作成し、次のコマンドを記録します。
    1. パイプラインと記述子セットをバインドします。
    2. コンピューティング ワークグループをディスパッチします。
  3. コマンド バッファをコンピューティング キューに送信します。
  4. キューで待機するか、必要に応じて同期フェンスを返します。

複数のカーネルをまとめて接続する(たとえば、ScriptGroup を使用してコードを移行する)には、これらを 1 つのコマンド バッファに記録し、メモリバリアと同期させます。

サンプルアプリでは、次の 2 つのコンピューティング タスクを紹介します。

  • HUE ローテーション: 単一のコンピューティング シェーダーを使用したシンプルなコンピューティング タスク。コードサンプルについては、ImageProcessor::rotateHue をご覧ください。
  • ぼかし: 2 つのコンピューティング シェーダーを順次実行する複雑なコンピューティング タスク。コードサンプルについては、ImageProcessor::blur をご覧ください。

コマンド バッファやメモリバリアについて詳しくは、Vulkan 仕様のコマンド バッファメモリバリアというセクションをご覧ください。