Android 12 以降、RenderScript API は非推奨となります。デバイス メーカーとコンポーネント メーカーはすでにハードウェア アクセラレーションのサポートの提供を終了しており、RenderScript のサポートは今後のリリースで完全に終了する予定です。
多くのユースケースでは、C / C++ のパフォーマンスで十分です。組み込み関数について RenderScript のみに依存している場合は、これらの使用を RenderScript 組み込み関数置換ツールキットで置き換えることができます。ツールキットは使いやすく、パフォーマンスを 2 倍向上させる可能性があります。
GPU アクセラレーションを最大限に活用する必要がある場合は、スクリプトを Vulkan に移行することをおすすめします。その他の高速化オプションとしては、スクリプトを OpenGL に移行する方法、キャンバス ベースの画像オペレーション、または Android グラフィック シェーディング言語(AGSL)の利用などがあります。
Android プラットフォームの RenderScript のサポート終了に伴い、Android Gradle プラグインの RenderScript のサポートも終了します。Android Gradle プラグイン 7.2 以降、RenderScript API のサポートは終了しています。RenderScript API は引き続き機能しますが、警告がトリガーされます。AGP の今後のバージョンでは、RenderScript のサポートが含まれなくなります。このガイドでは、RenderScript からの移行方法について説明します。
組み込み関数からの移行
RenderScript の組み込み関数は RenderScript のサポート終了後も引き続き機能しますが、実行できるのは GPU ではなく CPU に対してのみの可能性があります。
一部のオペレーションについては、より効率的なオプションがプラットフォームまたは Jetpack ライブラリに組み込まれました。
組み込みの高速画像オペレーション
Android プラットフォームは、RenderScript 組み込み関数とは無関係に、画像に適用できる高速画像処理オペレーションをサポートしています。次に例を示します。
- ブレンド
- ぼかし
- カラー マトリックス
- サイズ変更
Android 12 以降のビューへの画像ぼかし
Android 12(API レベル 31)では、ぼかしをサポートする RenderEffect
が追加され、RenderNode
にぼかしを入れることができるようになりました。RenderNode
は、Android がプラットフォーム グラフィックを高速化する際に使用するディスプレイ リストの構成です。
Android には、View
に関連付けられた RenderNode
に効果を適用するショートカットが用意されています。View
にぼかしを入れるには、View.setRenderEffect()
を呼び出します。
val blurRenderEffect = RenderEffect.createBlurEffect(radius, radius,
Shader.TileMode.MIRROR
)
view.setRenderEffect(blurRenderEffect)
Android 12 以降のビットマップにレンダリングされた画像ぼかし
ぼかしを入れた画像を Bitmap
にレンダリングする場合、フレームワークは HardwareBuffer
に基づく HardwareRenderer
での高速レンダリングをサポートしています。次のコードは、ぼかしの HardwareRenderer
、RenderNode
、RenderEffect
を作成します。
val imageReader = ImageReader.newInstance(
bitmap.width, bitmap.height,
PixelFormat.RGBA_8888, numberOfOutputImages,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or HardwareBuffer.USAGE_GPU_COLOR_OUTPUT
)
val renderNode = RenderNode("BlurEffect")
val hardwareRenderer = HardwareRenderer()
hardwareRenderer.setSurface(imageReader.surface)
hardwareRenderer.setContentRoot(renderNode)
renderNode.setPosition(0, 0, imageReader.width, imageReader.height)
val blurRenderEffect = RenderEffect.createBlurEffect(
radius, radius,
Shader.TileMode.MIRROR
)
renderNode.setRenderEffect(blurRenderEffect)
効果を適用するには、RenderNode
の内部 RecordingCanvas
を使用します。次のコードは、図形描画を記録してレンダリング リクエストを作成し、リクエストが完了するまで待ちます。
val renderCanvas = it.renderNode.beginRecording()
renderCanvas.drawBitmap(it.bitmap, 0f, 0f, null)
renderNode.endRecording()
hardwareRenderer.createRenderRequest()
.setWaitForPresent(true)
.syncAndDraw()
レンダリングされた画像は、ImageReader
に関連付けられた HardwareBuffer
内にあります。次のコードは、Image
を取得し、その HardwareBuffer
をラップする Bitmap
を返します。
val image = imageReader.acquireNextImage() ?: throw RuntimeException("No Image")
val hardwareBuffer = image.hardwareBuffer ?: throw RuntimeException("No HardwareBuffer")
val bitmap = Bitmap.wrapHardwareBuffer(hardwareBuffer, null)
?: throw RuntimeException("Create Bitmap Failed")
次のコードは、画像のレンダリング後にクリーンアップします。ImageReader
、RenderNode
、RenderEffect
、HardwareRenderer
を使用して複数の画像を処理できます。
hardwareBuffer.close()
image.close()
imageReader.close()
renderNode.discardDisplayList()
hardwareRenderer.destroy()
画像処理のための AGSL
Android 13 以降では、Android グラフィック シェーディング言語(AGSL)を使用して、プログラム可能な RuntimeShader
オブジェクトの動作を定義します。AGSL の構文の多くは GLSL フラグメント シェーダーと同じですが、Android グラフィック レンダリング システム内で動作して、Canvas
内の描画のカスタマイズと View
コンテンツのフィルタリングを行います。これを使用して図形描画オペレーション中にカスタム画像処理を追加できます。また、RenderNode
を直接使用して画像を Bitmap
キャンバスにレンダリングすることもできます。次の例は、カスタム シェーダーを適用して画像のぼかし効果を置き換える方法を示しています。
まず、RuntimeShader
を作成し、AGSL シェーダー コードでインスタンス化します。次のシェーダーは、色相回転のカラー マトリックスを適用するために使用されます。
val hueShader = RuntimeShader("""
uniform float2 iResolution; // Viewport resolution (pixels)
uniform float2 iImageResolution; // iImage1 resolution (pixels)
uniform float iRadian; // radian to rotate things around
uniform shader iImage1; // An input image
half4 main(float2 fragCoord) {
float cosR = cos(iRadian);
float sinR = sin(iRadian);
mat4 hueRotation =
mat4 (
0.299 + 0.701 * cosR + 0.168 * sinR, //0
0.587 - 0.587 * cosR + 0.330 * sinR, //1
0.114 - 0.114 * cosR - 0.497 * sinR, //2
0.0, //3
0.299 - 0.299 * cosR - 0.328 * sinR, //4
0.587 + 0.413 * cosR + 0.035 * sinR, //5
0.114 - 0.114 * cosR + 0.292 * sinR, //6
0.0, //7
0.299 - 0.300 * cosR + 1.25 * sinR, //8
0.587 - 0.588 * cosR - 1.05 * sinR, //9
0.114 + 0.886 * cosR - 0.203 * sinR, //10
0.0, //11
0.0, 0.0, 0.0, 1.0 ); //12,13,14,15
float2 scale = iImageResolution.xy / iResolution.xy;
return iImage1.eval(fragCoord * scale)*hueRotation;
}
""")
シェーダーは、他の RenderEffect
と同様に RenderNode
に適用できます。次の例は、hueShader でユニフォームを設定する方法を示しています。
hueShader.setFloatUniform("iImageResolution", bitmap.width.toFloat(),
bitmap.height.toFloat())
hueShader.setFloatUniform("iResolution", bitmap.width.toFloat(),
bitmap.height.toFloat())
hueShader.setFloatUniform("iRadian", radian)
hueShader.setInputShader( "iImage1", BitmapShader(bitmap, Shader.TileMode.MIRROR,
Shader.TileMode.MIRROR))
val colorFilterEffect = RenderEffect.createShaderEffect(it.hueShader)
renderNode.setRenderEffect(colorFilterEffect)
Bitmap
を取得するには、前述の画像ぼかしのサンプルと同じ手法を使用します。
RenderNode
の内部RecordingCanvas
でシェーダーを適用します。Image
が取得され、そのHardwareBuffer
をラップするBitmap
が返されます。
CameraX を使用した平面 YUV から RGB への変換
画像処理で使用するための平面 YUV から RGB への変換は、Jetpack の CameraX 内の ImageAnalysis ユースケースの一部としてサポートされています。
ImageAnalysis
の使用に関するリソースは、CameraX のスタートガイド Codelab の一部として、および Android カメラのサンプル リポジトリにあります。
RenderScript 組み込み関数置換ツールキット
アプリケーションで組み込み関数を使用する場合、スタンドアロンの代替ライブラリを使用できます。既存の RenderScript CPU 実装を使用するより高速であることがテストで確認されています。
ツールキットには次の関数が含まれています。
- ブレンド
- ぼかし
- カラー マトリックス
- 積和演算
- ヒストグラムと histogramDot
- ルックアップ テーブル(LUT)と LUT 3D
- サイズ変更
- YUV から RGB
詳細と制限事項については、ツールキットの README.md
ファイルと Toolkit.kt
. ファイルをご覧ください。
ライブラリをダウンロード、追加、使用するには、次の手順を実施します。
プロジェクトをダウンロードする 使用できます。
renderscript-toolkit module
を見つけてビルドします。アプリの
build.gradle
ファイルを変更して、Android Studio プロジェクトにライブラリを追加します。ツールキットの適切なメソッドを呼び出します。
例: ScriptIntrinsicBlur 関数から移行する
ScriptIntrinsicBlur
関数を置き換える手順は次のとおりです。
ビットマップのぼかし処理のために
Toolkit.blur
を呼び出します。var blurredBitmap = Toolkit.blur(myBitmap, radius)
バイトの配列で表現された画像のぼかし処理では、幅、高さ、ピクセルあたりのバイト数を指定します。
val outArray = Toolkit.blur(inputArray, bytesPerPixel, width, height, radius)
スクリプトからの移行
以下の方法でユースケースを解決できない場合:
- RenderScript 組み込み関数置換ツールキット
- Android プラットフォーム内の新しい API(
RenderEffect
、AGSL
など) - Android Jetpack ライブラリ API(
CameraX
など)
GPU アクセラレーションを利用できるユースケースの場合は、Android は、クロス プラットフォームの Vulkan API と OpenGL ES(GLES)API での GPU コンピューティングをサポートしています。ただし、ほとんどのデバイスでは、スクリプトは GPU ではなく CPU ですでに実行されているため、移行は不要かもしれません。ユースケースによっては、C / C++ は RenderScript、GLES、Vulkan による処理よりも速くなります(少なくともユースケースに十分な速度)。
移行方法を理解するには、サンプルアプリをご覧ください。このサンプルでは、RenderScript でビットマップのぼかし処理とカラー マトリックス変換を行う方法と、Vulkan と OpenGL を使用して同等のコードを作成する方法を説明します。
アプリでさまざまなリリースをサポートする必要がある場合は、Android 6(API レベル 23)以前を搭載したデバイスには RenderScript を使用し、Android 7(API レベル 24)以降を搭載したサポート デバイスでは Vulkan または GLES を使用します。minSdkVersion
が 24 以上の場合は、RenderScript を使用する必要はありません。GPU コンピューティングのサポートが必要な場合はいつでも Vulkan または GLES 3.1 を使用できます。
Android は GLES API 用の SDK バインディングを提供しているため、OpenGL ES で作業する場合は NDK を使用する必要はありません。
Vulkan は SDK バインディングを提供していないため、RenderScript から Vulkan へは直接マッピングされません。NDK を使用して Vulkan コードを記述し、Kotlin または Java からこのコードにアクセスする JNI 関数を作成します。
以降のページでは、RenderScript からの移行のさまざまな側面について説明します。サンプルアプリでは、これらの考慮事項をほぼすべてカバーしています。これらの考慮事項を理解するには、RenderScript と Vulkan の対応するコードを比較します。