Les API RenderScript sont obsolètes à partir d'Android 12. Les fabricants d'appareils et de composants ont déjà cessé de proposer la prise en charge de l'accélération matérielle. De plus, la compatibilité avec RenderScript devrait être complètement supprimée dans une prochaine version.
Les performances C/C++ peuvent être adaptées à de nombreux cas d'utilisation. Si vous dépendiez uniquement de RenderScript pour les fonctionnalités intrinsèques, vous pouvez les remplacer par le kit de remplacement des fonctionnalités intrinsèques de RenderScript, qui est plus facile à utiliser et qui multiplie par deux les performances.
Pour profiter pleinement de l'accélération du GPU, nous vous recommandons de migrer vos scripts vers Vulkan. Les autres options d'accélération incluent la migration de vos scripts vers OpenGL, l'utilisation d'opérations d'image basées sur Canvas et l'utilisation du langage AGSL (Android Graphics Language).
Suite à l'abandon de RenderScript sur la plate-forme Android, la prise en charge de RenderScript sera supprimée dans le plug-in Android Gradle. À partir de la version 7.2 du plug-in Android Gradle, les API RenderScript sont obsolètes. Elles continuent de fonctionner, mais déclenchent des avertissements. Les futures versions d'AGP ne prendront plus en charge RenderScript. Ce guide explique comment effectuer la migration depuis RenderScript.
Migrer depuis les fonctionnalités intrinsèques
Même si les fonctionnalités intrinsèques de RenderScript continuent à fonctionner après l'abandon de RenderScript, il est possible qu'elles ne puissent s'exécuter que sur le processeur et non plus sur le GPU.
Pour certaines de ces opérations, des options plus efficaces sont désormais intégrées à la plate-forme ou aux bibliothèques Jetpack.
Opérations d'image accélérées intégrées
La plate-forme Android prend en charge les opérations de traitement d'image accélérées qui peuvent être appliquées aux images, indépendamment des fonctionnalités intrinsèques de RenderScript. Exemples :
- Mélange
- Floutage
- Matrice de couleurs
- Redimensionner
Floutage d'image sous Android 12 ou version ultérieure dans une vue
RenderEffect
avec la prise en charge du floutage a été ajouté à Android 12 (niveau d'API 31). Il vous permet de flouter un RenderNode
. RenderNode
est une construction de la liste d'affichage utilisée par Android pour accélérer les graphismes de la plate-forme.
Android fournit un raccourci pour appliquer un effet au RenderNode
associé à une View
. Pour flouter une View
, appelez View.setRenderEffect()
:
val blurRenderEffect = RenderEffect.createBlurEffect(radius, radius,
Shader.TileMode.MIRROR
)
view.setRenderEffect(blurRenderEffect)
Floutage d'image sous Android 12 ou version ultérieure affiché dans un bitmap
Si vous souhaitez que l'image floutée soit affichée dans unBitmap
, le framework prend en charge le rendu accéléré avec un HardwareRenderer
appuyé par un HardwareBuffer
. Le code suivant crée le HardwareRenderer
, le RenderNode
et le RenderEffect
pour le floutage :
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)
L'application de l'effet implique l'utilisation du RecordingCanvas
interne pour le RenderNode
. Le code suivant enregistre le dessin, crée la requête de rendu, puis attend qu'elle soit terminée :
val renderCanvas = it.renderNode.beginRecording()
renderCanvas.drawBitmap(it.bitmap, 0f, 0f, null)
renderNode.endRecording()
hardwareRenderer.createRenderRequest()
.setWaitForPresent(true)
.syncAndDraw()
L'image affichée se trouve dans un HardwareBuffer
associé à l'ImageReader
. Le code suivant acquiert l'Image
et renvoie un Bitmap
qui encapsule son HardwareBuffer
.
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")
Le code suivant effectue un nettoyage après l'affichage de l'image. Notez que l'ImageReader
, le RenderNode
, le RenderEffect
et le HardwareRenderer
peuvent être utilisés pour traiter plusieurs images.
hardwareBuffer.close()
image.close()
imageReader.close()
renderNode.discardDisplayList()
hardwareRenderer.destroy()
AGSL pour le traitement d'image
Le langage AGSL (Android Graphics Shading Language) est utilisé par Android 13 et versions ultérieures pour définir le comportement des objets RuntimeShader
programmables. AGSL partage une grande partie de sa syntaxe avec les nuanceurs de fragment GLSL, mais fonctionne dans le système de rendu graphique Android pour personnaliser la peinture dans Canvas
et filtrer le contenu View
. Cela permet d'ajouter un traitement d'image personnalisé lors des opérations de dessin ou d'utiliser directement un RenderNode
pour afficher une image dans un canevas Bitmap
. L'exemple suivant montre comment appliquer un nuanceur personnalisé pour remplacer l'effet de floutage d'image.
Commencez par créer un RuntimeShader
, en l'instanciant avec le code du nuanceur AGSL. Ce nuanceur permet d'appliquer une matrice de couleurs pour la rotation des teintes :
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;
}
""")
Le nuanceur peut être appliqué à un RenderNode
, comme n'importe quel autre RenderEffect
.
L'exemple suivant montre comment définir les uniformes dans 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)
Pour obtenir le Bitmap
, la même technique est utilisée que dans l'exemple de floutage d'image précédent.
- Le
RecordingCanvas
interne pour leRenderNode
applique le nuanceur. - L'
Image
est acquise et renvoie unBitmap
qui encapsule sonHardwareBuffer
.
Convertir le format YUV planaire en RVB avec CameraX
La conversion du format YUV planaire en RVB pour le traitement d'image est prise en charge dans le cadre du cas d'utilisation ImageAnalysis dans CameraX de Jetpack.
Des ressources sur l'utilisation d'ImageAnalysis
sont disponibles dans l'atelier de programmation Premiers pas avec CameraX et dans le dépôt d'exemples d'appareils photo Android.
Kit de remplacement des fonctionnalités intrinsèques de Renderscript
Si votre application utilise des fonctionnalités intrinsèques, vous pouvez utiliser la bibliothèque de remplacement autonome. Cette option sera, d'après nos tests, plus rapide que d'utiliser la mise en œuvre existante du processeur RenderScript.
Ce kit comprend les fonctions suivantes :
- Mélange
- Floutage
- Matrice de couleurs
- Convoluer
- Histogramme et histogramDot
- Tableau de conversion (LUT) et LUT 3D
- Redimensionner
- YUV vers RVB
Pour en savoir plus et connaître les limites, consultez les fichiers README.md
et Toolkit.kt
du
kit.
Pour télécharger, ajouter et utiliser la bibliothèque, procédez comme suit :
Télécharger le projet depuis GitHub.
Localisez et créez le
renderscript-toolkit module
.Ajoutez la bibliothèque à votre projet Android Studio en modifiant le fichier
build.gradle
de l'application.Appelez la méthode appropriée dans le kit.
Exemple : Migrer depuis la fonction ScriptIntrinsicBlur
Pour remplacer la fonction ScriptIntrinsicBlur
:
Pour flouter un bitmap, appelez
Toolkit.blur
.var blurredBitmap = Toolkit.blur(myBitmap, radius)
Si vous souhaitez flouter une image représentée par un tableau d'octets, spécifiez la largeur, la hauteur et le nombre d'octets par pixel.
val outArray = Toolkit.blur(inputArray, bytesPerPixel, width, height, radius)
Migrer depuis les scripts
Si votre cas d'utilisation ne peut pas être résolu avec :
- Le kit de remplacement des fonctionnalités intrinsèques de RenderScript
- Les nouvelles API de la plate-forme Android, telles que
RenderEffect
etAGSL
- Les API de la bibliothèque Android Jetpack telles que
CameraX
Et si votre cas d'utilisation peut bénéficier de l'accélération du GPU, Android prend en charge les calculs GPU sur les API multiplates-formes Vulkan et OpenGL ES (GLES). Cela peut s'avérer inutile, car sur la plupart des appareils, vos scripts s'exécutent déjà sur le processeur plutôt que sur le GPU : C/C++ peut être plus rapide que les calculs RenderScript, GLES ou Vulkan dans certains cas d'utilisation (ou du moins assez rapide pour votre cas d'utilisation).
Pour mieux comprendre comment effectuer la migration, consultez l'application exemple. L'exemple montre comment flouter un bitmap et effectuer une conversion de la matrice de couleurs dans RenderScript, et présente un code équivalent dans Vulkan et OpenGL.
Si votre application doit prendre en charge plusieurs versions, utilisez RenderScript pour les appareils équipés d'Android 6 (niveau d'API 23) ou version antérieure, et Vulkan ou GLES sur les appareils compatibles équipés d'Android 7 (niveau d'API 24) ou version ultérieure. Si vous utilisez minSdkVersion
24 ou ultérieure, vous n'aurez peut-être pas besoin d'utiliser RenderScript. Vulkan ou GLES 3.1 peuvent être utilisés partout où vous avez besoin de capacités de calcul GPU.
Android fournit des liaisons SDK pour les API GLES. Il n'est donc pas nécessaire d'utiliser le NDK lorsque vous travaillez dans OpenGL ES.
Vulkan ne fournit pas de liaisons SDK. Il n'y a donc pas de mappage direct de RenderScript vers Vulkan. Vous écrivez le code Vulkan à l'aide du NDK et créez des fonctions JNI pour accéder à ce code depuis Kotlin ou Java.
Les pages suivantes traitent des aspects de la migration depuis RenderScript. L'application exemple met en œuvre pratiquement toutes ces considérations. Pour mieux les comprendre, comparez le code RenderScript et le code équivalent Vulkan.