Cómo migrar desde RenderScript

Las API de RenderScript dejaron de estar disponibles a partir de Android 12. Seguirán funcionando, pero estimamos que los fabricantes de dispositivos y componentes dejarán de proporcionar compatibilidad con la aceleración de hardware conforme pase el tiempo. Para aprovechar al máximo la aceleración de GPU, te recomendamos que migres tus secuencias de comandos a Vulkan o uses nuestro kit de herramientas de reemplazo para migrar de las funciones intrínsecas.

Luego de que RenderScript deje de estar disponible en la plataforma de Android, también quitaremos la compatibilidad con RenderScript en el complemento de Android para Gradle. A partir del complemento de Android para Gradle 7.2, las API de RenderScript dejaron de estar disponibles. Seguirán funcionando, pero invocarán advertencias y se quitarán por completo en versiones futuras de AGP. En esta guía, se explica cómo migrar desde RenderScript.

Cómo migrar desde funciones intrínsecas

Aunque las funciones intrínsecas de RenderScript seguirán funcionando después de que RenderScript deje de estar disponible, es posible que solo se ejecuten en la CPU y no en la GPU.

Si tu aplicación utiliza estas funciones, puedes usar la biblioteca de reemplazo independiente. Nuestras pruebas indican que esto es más rápido que usar la implementación de CPU de RenderScript existente.

El kit de herramientas incluye las siguientes funciones:

  • Mezcla
  • Desenfoque
  • Matriz de color
  • Convolución
  • Histograma e histogramDot
  • Tabla de consulta (LUT) y LUT 3D
  • Cambiar tamaño
  • YUV a RGB

Si deseas conocer información detallada y las limitaciones, consulta los archivos README.md y Toolkit.kt del kit de herramientas .

Realiza los siguientes pasos para descargar, agregar y usar la biblioteca:

  1. Descarga el proyecto desde GitHub.

  2. Ubica y compila el renderscript-toolkit module.

  3. Para agregar la biblioteca a tu proyecto de Android Studio, modifica el archivo build.gradle de la app.

  4. Invoca el método adecuado del kit de herramientas.

Ejemplo: Cómo migrar de la función ScriptIntrinsicBlur

A fin de reemplazar la función ScriptIntrinsicBlur, sigue estos pasos:

  • Desenfoca el mapa de bits llamando a Toolkit.blur.

    var blurredBitmap = Toolkit.blur(myBitmap, radius)
    
  • Si deseas desenfocar una imagen representada por un array de bytes, especifica el ancho, el alto y la cantidad de bytes por píxel.

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

Cuando orientes tu contenido a Android 12 (nivel de API 31) y versiones posteriores, procura usar la clase RenderEffect en lugar de Toolkit.blur().

Cómo migrar desde secuencias de comandos

Para aprovechar al máximo la aceleración de GPU, te recomendamos que migres las secuencias de comandos de RenderScript a la API multiplataforma de Vulkan. Aunque tus secuencias de comandos seguirán ejecutándose incluso si no migras, podrían ejecutarse en la CPU en lugar de hacerlo en la GPU según la disponibilidad de los controladores.

Si deseas comprender mejor cómo migrar la funcionalidad, revisa la app de ejemplo, que muestra cómo desenfocar un mapa de bits y realizar una conversión de matriz de color en RenderScript, y tiene código equivalente en Vulkan.

Si tu aplicación necesita ser compatible con una variedad de versiones, usa RenderScript para dispositivos con Android 9 (nivel de API 28) y versiones anteriores, y Vulkan para Android 10 (nivel de API 29) y versiones posteriores.

Vulkan no proporciona las API de Kotlin o Java, por lo que no hay una asignación directa de RenderScript a Vulkan. Deberás escribir el código de Vulkan con el NDK y crear funciones de JNI a fin de acceder a este código desde Kotlin o Java.

En las siguientes secciones, se describen los aspectos de la migración de RenderScript. En la app de ejemplo, se implementan casi todas estas consideraciones. Para entenderlas mejor, compara el código equivalente de RenderScript y Vulkan.

Inicialización

En lugar de crear un objeto de contexto de RenderScript en Kotlin o Java, realiza los siguientes pasos a fin de crear un contexto de Vulkan con el NDK.

  1. Crea una instancia de Vulkan.

  2. Elige un dispositivo físico de Vulkan que admita una cola de procesamiento.

  3. Crea un dispositivo lógico de Vulkan y obtén la cola de procesamiento.

Opcionalmente, puedes configurar las capas de validación de Vulkan en Android a los efectos de acelerar el desarrollo de tus aplicaciones de Vulkan.

En la app de ejemplo, se muestra cómo inicializar el contexto de Vulkan en VulkanContext.h. Si deseas obtener más información, consulta las secciones Inicialización y Dispositivos y colas de la especificación de Vulkan.

Asignaciones

Puedes migrar una asignación de RenderScript a una imagen de almacenamiento de Vulkan o a un búfer de almacenamiento de Vulkan. Si deseas obtener un mejor rendimiento con imágenes de solo lectura, usa una imagen de ejemplo con operaciones de recuperación, ya sea como un muestreo de imágenes combinadas o con vinculaciones específicas de muestreo e imagen de muestra.

Los recursos de Vulkan se asignan en Vulkan. A fin de evitar la sobrecarga de copia de memoria cuando interactúas con otros componentes de Android, procura usar la extensión VK_ANDROID_external_memory_android_hardware_buffer para importar un AHardwareBuffer de Android a Vulkan. Esta extensión está disponible en todos los dispositivos Android que admiten Vulkan 1.1. Si deseas obtener información detallada, consulta FEATURE_VULKAN_HARDWARE_VERSION.

En la app de ejemplo, se muestra cómo crear recursos de Vulkan en VulkanResources.h. Para obtener más información, consulta las secciones sobre la creación de recursos y los descriptores de recursos de la especificación de Vulkan.

Secuencias de comandos

Tus secuencias de comandos de RenderScript deben convertirse a sombreadores de cómputos de Vulkan. Es posible que también debas adaptar tu código en función del uso de globales de RenderScript.

Escribe un sombreador de cómputos de Vulkan

Por lo general, un sombreador de cómputos de Vulkan se escribe en OpenGL Shading Language (GLSL) y, luego, se compila en el formato Standard Portable Intermediate Representation-V (SPIR-V).

Si deseas obtener información detallada e instrucciones para integrar sombreadores en tu app, consulta Compiladores de sombreadores de Vulkan en Android.

Adaptación de globales de secuencias de comandos

Según las características de los globales de secuencias de comandos, te recomendamos que uses constantes de especialización, constantes push u objetos de búfer uniformes para globales que no se modifiquen dentro del sombreador:

  • Constantes de especialización: Se recomiendan para los globales de secuencias de comandos que son mayormente coherentes entre las invocaciones de kernel. Si se modifica el valor de las constantes de especialización, se deberá volver a crear la canalización de cómputos.
  • Constantes push: Se recomiendan para globales de secuencias de comandos que cambian con frecuencia y cuyo tamaño es menor a maxPushConstantsSize (mínimo garantizado de 128 bytes).
  • Búfer uniforme: Se recomienda para globales de secuencias de comandos que cambian con frecuencia y cuyo tamaño es mayor al límite de constante push.

Para los globales que se modifican dentro del sombreador, puedes usar la imagen de almacenamiento de Vulkan o el búfer de almacenamiento de Vulkan.

Cómputos

Deberás crear una canalización de cómputos de Vulkan de modo que la GPU ejecute tu sombreador de cómputos.

Crea una canalización de cómputos de Vulkan

El archivo ComputePipeline.h de la app de ejemplo muestra cómo crear la canalización de cómputos de Vulkan.

Para usar un sombreador SPIR-V compilado en Vulkan, crea una canalización de cómputos de Vulkan de la siguiente manera:

  1. Crea un módulo de sombreador que tenga el sombreador SPIR-V compilado.
  2. Crea un diseño del conjunto de descriptores que especifique las vinculaciones de recursos (si deseas obtener información detallada, consulta Asignaciones).
  3. Crea un conjunto de descriptores a partir del diseño de ese conjunto.
  4. Crea un diseño de canalización a partir del diseño del conjunto de descriptores.
  5. Crea una canalización de cómputos con el módulo de sombreador y el diseño de la canalización.

Si deseas obtener más información, consulta la sección Canalizaciones de cómputos en la especificación de Vulkan.

Inicia un cómputo

Para iniciar el cómputo mediante una canalización de cómputos, haz lo siguiente:

  1. Actualiza el conjunto de descriptores con los recursos de Vulkan.
  2. Crea un búfer de comandos de Vulkan y registra los siguientes comandos:
    1. Vincula la canalización y el conjunto de descriptores.
    2. Despacha los grupos de trabajo de cómputos.
  3. Envía el búfer de comandos a la cola de procesamiento.
  4. Espera en la cola o, de manera opcional, muestra una valla de sincronización.

A fin de encadenar varios kernels (por ejemplo, para migrar códigos mediante ScriptGroup), regístralos en un solo búfer de comando y sincronízalos con las barreras de memoria.

En la app de ejemplo, se muestran dos tareas de cómputos:

  • Rotación de tonalidad: Es una tarea de cómputos simple con un solo sombreador de cómputos. Consulta ImageProcessor::rotateHue para ver la muestra de código.
  • Desenfoque: Es una tarea de cómputos más compleja que ejecuta dos sombreadores de cómputos en forma secuencial. Consulta ImageProcessor::blur para ver la muestra de código.

Si deseas obtener más información sobre los búferes de comandos o las barreras de memoria, consulta las secciones Búferes de comando y Barreras de memoria de la especificación de Vulkan.