Введение в Renderscript
В этом руководстве вы познакомитесь с Renderscript и узнаете, как использовать встроенный API Renderscript в приложении Xamarin.Android, нацеленном на API уровня 17 или выше.
Обзор
Платформа программирования Renderscript создана корпорацией Google в целях повышения производительности приложений Android, которые требуют обширных вычислительных ресурсов. Это высокопроизводительный низкоуровневый API, основанный на C99. Так как это интерфейс API низкого уровня, который может работать на ЦП, GPU или DSP, Renderscript хорошо подходит для приложений Android, выполняющих любые из следующих задач:
- Графика
- Обработка изображений
- Шифрование
- обработка сигналов;
- математические функции.
Renderscript использует clang
и компилирует скрипты в байтовый код LLVM, упакованный в формат APK. При первом запуске приложения байтовый код LLVM компилируется в машинный код для конкретных процессоров на устройстве. Такая архитектура позволяет приложению Android использовать все преимущества машинного кода, не вынуждая разработчиков самостоятельно писать код для каждого процессора на используемых устройствах.
Подпрограмма Renderscript содержит два компонента.
Среда выполнения Renderscript — это собственные API, которые отвечают за выполнение отрисовки. Сюда входят все скрипты Renderscript, написанные для приложения.
Управляемые оболочки из Android Framework — управляемые классы, позволяющие приложению Android управлять средой выполнения и скриптами Renderscript и взаимодействовать с ней. В дополнение к классам, предоставленным платформой для управления средой выполнения Renderscript, цепочка инструментов Android создаст управляемые классы-оболочки для использования в приложении Android, изучив исходный код Renderscript.
На схеме ниже показана взаимосвязь этих компонентов.
Существуют три важных понятия, связанных с использованием скриптов Renderscript в приложении Android.
Контекст — управляемый API, предоставляемый пакетом SDK для Android, который выделяет ресурсы для Renderscript и позволяет приложению Android передавать и получать данные из Renderscript.
Вычислительное ядро — также известное как корневое ядро или ядро, это подпрограмма, которая выполняет работу. Ядро схоже с функцией в C; это подпрограммы с возможностью параллельного выполнения, которая вызывается для всех данных в выделенной памяти.
Выделенная память — данные передаются в ядро и из нее через выделение. Ядро может иметь одно входное и (или) одно выходное распределение.
Пространство имен Android.Renderscripts содержит классы для взаимодействия со средой выполнения Renderscript. В частности, класс Renderscript
управляет жизненным циклом и ресурсами подсистемы Renderscript. Приложение Android должно инициализировать один или несколько объектов Android.Renderscripts.Allocation
Объектов. Управляемый API Распределения отвечает за выделение памяти и доступ к ней для совместного использования приложением Android и средой выполнения Renderscript. Как правило, создается одно распределение для входных данных и при необходимости еще одно для хранения выходных данных ядра. Подсистема среды выполнения Renderscript и связанные управляемые классы-оболочки самостоятельно управляют доступом к памяти распределений, и разработчику приложения Android не нужно ничего с этим делать.
Распределение может содержать один или несколько элементов Android.Renderscripts.Elements. Элементами называют специализированный тип, который описывает данные в каждом распределении. Типы элементов для выходного распределения должны соответствовать типам входного элемента. При выполнении Renderscript параллельно циклически перебирает все элементы во входном распределении и сохраняет результаты в выходное распределение. Существуют два типа элементов:
простой тип — концептуально это то же, что и тип данных C или
float
.char
сложный тип — этот тип похож на C
struct
.
Подсистема Renderscript выполнит проверку среды выполнения, чтобы убедиться, что элементы в каждом распределении совместимы с требованиями ядра. Если тип данных для элементов в распределении не соответствует ожидаемому ядром типу, будет создано исключение.
Все ядра Renderscript помещаются в оболочку типа, который наследует от класса КлассAndroid.Renderscripts.Script
. Класс Script
используется для задания параметров для Renderscript, установки соответствующих Allocations
и запуска Renderscript. В пакет SDK для Android входят два подкласса Script
:
Android.Renderscripts.ScriptIntrinsic
— Некоторые из более распространенных задач Renderscript упаковываются в пакет SDK для Android и доступны подклассом класса ScriptIntrinsic . Разработчику не нужно предпринимать дополнительных действий, чтобы использовать эти скрипты в своем приложении, так как они уже предоставлены.ScriptC_XXXXX
— Также известны как пользовательские скрипты, это скрипты, написанные разработчиками и упакованные в APK. Во время компиляции цепочка инструментов Android создаст управляемые классы-оболочки, которые позволят использовать эти скрипты в приложении Android. Имена для создаваемых классов составляются из имени файла Renderscript с префиксомScriptC_
. Написание и внедрение пользовательских скриптов официально не поддерживается в Xamarin.Android и не входит в задачи этого руководства.
Из этих двух типов в Xamarin.Android поддерживается только StringIntrinsic
. В этом руководстве рассказывается, как использовать встроенные скрипты в приложении Xamarin.Android.
Требования
Это руководство применимо к приложениям Xamarin.Android, нацеленным на API уровня 17 или выше. Использование пользовательских скриптов в этом руководстве не рассматривается.
Библиотека поддержки Xamarin.Android версии 8 обеспечивает обратную совместимость API Renderscript с приложениями, которые нацеливаются на более старые версии пакета SDK для Android. Добавление этого пакета в проект Xamarin.Android позволит разрешить приложениям, нацеленным на более старый пакет SDK для Android, использовать встроенные скрипты.
Использование встроенных скриптов Renderscript в Xamarin.Android
Встроенные скрипты отлично подходят для выполнения задач с высокой вычислительной нагрузкой, позволяя почти не создавать новый код. Они уже оптимизированы для оптимальной производительности на большом числе разнообразных устройств. Вполне нормально, что встроенный скрипт выполняется в 10 раз быстрее, чем управляемый код, и примерно в 2–3 раза быстрее пользовательской реализации на C. Встроенные скрипты покрывают широкий спектр типичных вычислительных сценариев. Вот список встроенных скриптов в текущей версии Xamarin.Android:
ScriptIntrinsic3DLUT — преобразует RGB в RGBA с помощью таблицы подстановки трехмерного формата.
ScriptIntrinsicBLAS — предоставление API-интерфейсов Renderscript производительности в BLAS. Программы BLAS (Basic Linear Algebra Subprograms) предоставляют стандартные строительные блоки для базовых векторных и матричных операций.
ScriptIntrinsicBlend — сочетание двух выделений вместе.
ScriptIntrinsicBlur — применяет размытие Gaussian к выделению.
ScriptIntrinsicColorMatrix — применяет цветовую матрицу к выделению (т. е. изменение цветов, изменение цвета, изменение оттенка).
ScriptIntrinsicConvolve3x3 — применяет цветовую матрицу 3x3 к выделению.
ScriptIntrinsicConvolve5x5 — применяет цветовую матрицу 5x5 к выделению.
ScriptIntrinsicHistogram — встроенный фильтр гистограммы.
ScriptIntrinsicLUT — применяет таблицу подстановки для каждого канала к буферу.
ScriptIntrinsicResize — скрипт для выполнения изменения размера распределения 2D.
ScriptIntrinsicYuvToRGB — преобразует буфер YUV в RGB.
Подробные сведения о каждом из встроенных скриптов вы найдете в документации по API.
Далее описаны базовые процедуры для применение Renderscript в приложении Android.
Создание контекста Renderscript — Renderscript
класс — это управляемая оболочка вокруг контекста Renderscript и будет управлять инициализацией, управлением ресурсами и очисткой. Объект Renderscript создается с помощью фабричного метода RenderScript.Create
, который принимает в качестве параметра контекст выполнения Android (например, действие). Следующая строка кода демонстрирует инициализацию контекста выполнения Renderscript:
Android.Renderscripts.RenderScript renderScript = RenderScript.Create(this);
Создание выделений — в зависимости от встроенного скрипта может потребоваться создать один или два Allocation
. Токен Android.Renderscripts.Allocation
Класс имеет несколько методов фабрики, помогающих создать экземпляр выделения для встроенной функции. В следующем примере кода показано, как создать распределение для растровых изображений.
Android.Graphics.Bitmap originalBitmap;
Android.Renderscripts.Allocation inputAllocation = Allocation.CreateFromBitmap(renderScript,
originalBitmap,
Allocation.MipmapControl.MipmapFull,
AllocationUsage.Script);
Часто приходится создавать Allocation
для хранения выходных данных скрипта. Следующий фрагмент кода демонстрирует создание вспомогательного метода Allocation.CreateTyped
для создания второго экземпляра Allocation
с тем же типом, что у исходного.
Android.Renderscripts.Allocation outputAllocation = Allocation.CreateTyped(renderScript, inputAllocation.Type);
Создание экземпляра оболочки скрипта — каждый из встроенных классов оболочки скрипта должен иметь вспомогательные методы (обычно называемые Create
)для создания экземпляра объекта-оболочки для этого скрипта. В следующем фрагменте кода приведен пример создания экземпляра для объекта размытия ScriptIntrinsicBlur
. Вспомогательный метод Element.U8_4
создает элемент, который описывает тип данных с 4 8-битовыми полями для хранения целых чисел без знака, что соответствует данным для объекта Bitmap
:
Android.Renderscripts.ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.Create(renderScript, Element.U8_4(renderScript));
Назначение выделений, задание параметров и запуск скрипта — Script
класс предоставляет ForEach
метод для фактического запуска Renderscript. Этот метод последовательно перебирает все Element
в Allocation
, где хранятся входные данные. В некоторых случаях может потребоваться создать еще один Allocation
для выходных данных.
ForEach
перезаписывает содержимое выходного распределения. Продолжая работу с фрагментами кода из предыдущих шагов, этот пример демонстрирует назначение входного распределения, настройку параметра и выполнение скрипта (который копирует результаты в выходное распределение).
blurScript.SetInput(inputAllocation);
blurScript.SetRadius(25); // Set a pamaeter
blurScript.ForEach(outputAllocation);
Возможно, вас заинтересует рецепт размытия изображения с помощью Renderscript, который содержит полный пример программы с использованием встроенного скрипта Xamarin.Android.
Итоги
В этом руководстве представлены базовые сведения о Renderscript и показано, как использовать его в приложении Xamarin.Android. Здесь кратко описана суть Renderscript и взаимодействие с приложением Android. Также здесь описаны некоторые важные компоненты Renderscript и важные различия между пользовательскими скриптами и встроенными скриптами. И наконец, обсуждается процесс применения встроенных скриптов в приложении Xamarin.Android.