Introducción a Renderscript

En esta guía se presenta Renderscript y se explica cómo usar las API intrínsecas de Renderscript en una aplicación Xamarin.Android que tiene como destino el nivel de API 17 o posterior.

Información general

Renderscript es un marco de programación creado por Google con el fin de mejorar el rendimiento de las aplicaciones Android que requieren recursos de cálculo extensivos. Se trata de una API de bajo nivel y alto rendimiento basada en C99. Dado que se trata de una API de bajo nivel que se ejecutará en CPU, GPU o DSP, Renderscript es adecuado para aplicaciones Android que pueden necesitar realizar cualquiera de las siguientes acciones:

  • Elementos gráficos
  • Procesamiento de imagen
  • Cifrado
  • Procesamiento de señales
  • Rutinas matemáticas

Renderscript usará clang y compilará los scripts en el código de bytes de LLVM que se agrupa en APK. Cuando la aplicación se ejecuta por primera vez, el código de bytes de LLVM se compilará en el código máquina para los procesadores del dispositivo. Esta arquitectura permite a una aplicación Android aprovechar las ventajas del código máquina sin que los desarrolladores tengan que escribirlo para cada procesador en el propio dispositivo.

Hay dos componentes en una rutina de Renderscript:

  1. Renderscript en tiempo de ejecución: se trata de las API nativas responsables de ejecutar Renderscript. Esto incluye cualquier script Renderscript escrito para la aplicación.

  2. Contenedores administrados desde el marco de trabajo de Android: clases administradas que permiten a una aplicación Android controlar e interactuar con los scripts y el tiempo de ejecución de Renderscript. Además de las clases proporcionadas en el marco para controlar el tiempo de ejecución de Renderscript, la cadena de herramientas de Android examinará el código fuente de Renderscript y generará clases contenedoras administradas para que la aplicación Android las use.

El siguiente diagrama ilustra cómo se relacionan estos componentes:

Diagram illustrating how the Android Framework interacts with the Renderscript Runtime

Hay tres conceptos importantes para el uso de Renderscripts en una aplicación Android:

  1. Un contexto: una API administrada proporcionada por Android SDK que asigna recursos a Renderscript y permite a la aplicación Android pasar y recibir datos desde Renderscript.

  2. Un kernel de proceso: también conocido como kernel raíz o kernel, que es una rutina que realiza el trabajo. El kernel es muy similar a una función de C; se trata de una rutina paralelizable que se ejecutará en todos los datos de la memoria asignada.

  3. Memoria asignada: los datos se pasan a y desde un kernel a través de una asignación. Un kernel puede tener una asignación de entrada o de salida.

El espacio de nombres Android.Renderscripts contiene las clases para interactuar con el tiempo de ejecución de Renderscript. En concreto, la clase Renderscript administrará el ciclo de vida y los recursos del motor de Renderscript. La aplicación Android debe inicializar uno o más objetos Objetos Android.Renderscripts.Allocation. Una asignación es una API administrada que es responsable de la asignación y el acceso a la memoria que se comparte entre la aplicación Android y el tiempo de ejecución de Renderscript. Normalmente, se crea una asignación para la entrada y, opcionalmente, se crea otra asignación que contiene la salida del kernel. El motor en tiempo de ejecución de Renderscript y las clases contenedoras administradas asociadas administrarán el acceso a la memoria mantenida por las asignaciones; no es necesario que un desarrollador de aplicaciones Android realice ningún trabajo adicional.

Una asignación contendrá uno o varios elementos Android.Renderscripts.Elements. Los elementos son un tipo especializado que describen los datos de cada asignación. Los tipos del elemento de la asignación de salida deben coincidir con los tipos del elemento de entrada. Al realizar la ejecución, un elemento Renderscript iterará en cada elemento de la asignación de entrada en paralelo y escribirá los resultados en la asignación de salida. Hay dos tipos de elementos:

  • Tipo simple: conceptualmente, es igual que un tipo de datos de C, float o char.

  • Tipo completo: este tipo es similar a un elemento struct de C.

El motor de Renderscript realizará una comprobación en tiempo de ejecución para asegurarse de que los elementos de cada asignación son compatibles con lo que necesita el kernel. Si el tipo de datos de los elementos de la asignación no coincide con el tipo de datos que el kernel espera, se producirá una excepción.

Todos los kernels de Renderscript se encapsularán mediante un tipo que sea un descendiente de .ClaseAndroid.Renderscripts.Script . La clase Script se usa para establecer los parámetros de un elemento Renderscript, establecer el elemento Allocationsadecuado y ejecutar Renderscript. Hay dos subclases Script en Android SDK:

  • Android.Renderscripts.ScriptIntrinsic: algunas de las tareas más comunes de Renderscript se encapsulan en Android SDK, y una subclase de la clase ScriptIntrinsic puede acceder a ellas. No es necesario que un desarrollador realice pasos adicionales para usar estos scripts en su aplicación, puesto que ya se proporcionan.

  • ScriptC_XXXXX: también se conoce como scripts de usuario; son scripts escritos por desarrolladores y empaquetados en el APK. En tiempo de compilación, la cadena de herramientas de Android generará clases contenedoras administradas que permitirán usar los scripts en la aplicación Android. El nombre de estas clases generadas es el nombre del archivo de Renderscript, con el prefijo ScriptC_. La escritura e incorporación de scripts de usuario no es compatible oficialmente con Xamarin.Android y va más allá del ámbito de esta guía.

De estos dos tipos, Xamarin.Android solo admite StringIntrinsic. En esta guía se explica cómo usar scripts intrínsecos en una aplicación Xamarin.Android.

Requisitos

Esta guía está destinada a las aplicaciones Xamarin.Android que tienen como destino el nivel de API 17 o posterior. El uso de scripts de usuario no se trata en esta guía.

La biblioteca de compatibilidad de Xamarin.Android V8 transporta las API de Renderscript intrínsecas para las aplicaciones destinadas a versiones anteriores de Android SDK. Agregar este paquete a un proyecto de Xamarin.Android debe permitir que las aplicaciones destinadas a versiones anteriores de Android SDK aprovechen los scripts intrínsecos.

Usar Renderscripts intrínsecos en Xamarin.Android

Los scripts intrínsecos son una excelente manera de realizar tareas informáticas intensivas con una cantidad mínima de código adicional. Se han optimizado para ofrecer un rendimiento óptimo en una gran sección de dispositivos cruzados. No es raro que un script intrínseco se ejecute 10 veces más rápido que el código administrado y 2 o 3 veces más tarde que una implementación personalizada de C. Muchos de los escenarios de procesamiento típicos están incluidos en los scripts intrínsecos. Esta lista de los scripts intrínsecos describe los scripts actuales de Xamarin.Android:

Consulte la documentación de la API para obtener más información sobre cada uno de los scripts intrínsecos.

A continuación, se describen los pasos básicos para usar Renderscript en una aplicación Android.

Creación de un contexto de Renderscript: la clase Renderscript es un contenedor administrado en torno al contexto de Renderscript y controlará la inicialización, la administración de recursos y la limpieza. El objeto de Renderscript se crea mediante el método Factory Method RenderScript.Create, que adopta un contexto de Android (como una actividad) como parámetro. En la siguiente línea de código se muestra cómo inicializar el contexto de Renderscript:

Android.Renderscripts.RenderScript renderScript = RenderScript.Create(this);

Creación de asignaciones: según el script intrínseco, puede que sea necesario crear uno o dos elementos Allocation. ElLa clase Android.Renderscripts.Allocation tiene varios métodos Factory Method para facilitar la creación de instancias de una asignación para un elemento intrínseco. Como ejemplo, el fragmento de código siguiente muestra cómo crear una asignación para los mapas de bits.

Android.Graphics.Bitmap originalBitmap;
Android.Renderscripts.Allocation inputAllocation = Allocation.CreateFromBitmap(renderScript,
                                                     originalBitmap,
                                                     Allocation.MipmapControl.MipmapFull,
                                                     AllocationUsage.Script);

A menudo, será necesario crear un elemento Allocation para contener los datos de salida de un script. En el siguiente fragmento de código se muestra cómo usar la aplicación auxiliar de Allocation.CreateTyped para crear instancias de un segundo elemento Allocation que sea del mismo tipo que el original:

Android.Renderscripts.Allocation outputAllocation = Allocation.CreateTyped(renderScript, inputAllocation.Type);

Creación de una instancia del contenedor de scripts: cada una de las clases contenedoras de scripts intrínsecos debe tener métodos auxiliares (normalmente denominados Create) para crear instancias de un objeto contenedor para ese script. El siguiente fragmento de código es un ejemplo de cómo crear una instancia de un objeto de desenfoque ScriptIntrinsicBlur. El método auxiliar Element.U8_4 creará un elemento que describe un tipo de datos que es 4 campos de valores enteros de 8 bits sin signo, adecuado para contener los datos de un objeto Bitmap:

Android.Renderscripts.ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.Create(renderScript, Element.U8_4(renderScript));

Realizar asignaciones, establecer parámetros y ejecutar scripts: la clase Script ofrece un método ForEach para ejecutar realmente Renderscript. Este método iterará en cada Element de Allocation que contiene los datos de entrada. En algunos casos, puede ser necesario proporcionar un elemento Allocation que contiene la salida. ForEach sobrescribirá el contenido de la asignación de salida. Para continuar con los fragmentos de código de los pasos anteriores, este ejemplo muestra cómo realizar una asignación de entrada, establecer un parámetro y, por último, ejecutar el script (copiando los resultados en la asignación de salida):

blurScript.SetInput(inputAllocation);
blurScript.SetRadius(25);  // Set a pamaeter
blurScript.ForEach(outputAllocation);

Puede consultar el artículo Desenfoque de una imagen con Renderscript, ya que se trata de un ejemplo completo de cómo usar un script intrínseco de Xamarin.Android.

Resumen

En esta guía se ha presentado Renderscript y cómo usarlo en una aplicación Xamarin.Android. Describe brevemente qué es Renderscript y cómo funciona en una aplicación Android. Describe algunos de los componentes clave de Renderscript y la diferencia entre scripts de usuario y scripts intrínsecos. Por último, en esta guía se describen los pasos para usar un script intrínseco en una aplicación Xamarin.Android.