API-интерфейсы RenderScript устарели, начиная с Android 12. Производители устройств и компонентов уже прекратили предоставлять поддержку аппаратного ускорения, и ожидается, что поддержка RenderScript будет полностью удалена в будущем выпуске.
Производительности C/C++ может быть достаточно для многих случаев использования, и если вы полагались только на RenderScript для встроенных функций, вы можете заменить это использование набором инструментов замены RenderScript Intrinsics , который проще в использовании и потенциально повышает производительность в 2 раза!
Если вам необходимо в полной мере воспользоваться преимуществами ускорения графического процессора, мы рекомендуем перенести ваши сценарии в Vulkan . Другие варианты ускорения включают миграцию ваших сценариев в OpenGL , использование операций с изображениями на основе Canvas или использование языка шейдинга графики Android (AGSL) .
После прекращения поддержки RenderScript на платформе Android поддержка RenderScript удаляется из плагина Android Gradle. Начиная с плагина Android Gradle 7.2, API RenderScript устарели. Они продолжают работать, но вызывают предупреждения. Будущие версии AGP больше не будут включать поддержку Renderscript. В этом руководстве объясняется, как перейти с RenderScript.
Миграция с встроенных функций
Хотя внутренние функции RenderScript продолжают работать после прекращения поддержки RenderScript, они могут выполняться только на ЦП, а не на графическом процессоре.
Для некоторых из этих операций теперь есть более эффективные варианты, встроенные в платформу или в библиотеки Jetpack.
Встроенные ускоренные операции с изображениями
Платформа Android поддерживает операции ускоренной обработки изображений, которые можно применять к изображениям независимо от встроенных функций RenderScript. Примеры включают в себя:
- Смешивать
- Размытие
- Цветовая матрица
- Изменить размер
Размытие изображения на Android 12+ в представлении
RenderEffect
с поддержкой размытия был добавлен в Android 12, уровень API 31, что позволяет размыть RenderNode
. RenderNode
— это конструкция списка отображения, которую Android использует для ускорения графики платформы.
Android предоставляет ярлык для применения эффекта к RenderNode
связанному с View
. Чтобы размыть View
, вызовите View.setRenderEffect()
:
val blurRenderEffect = RenderEffect.createBlurEffect(radius, radius,
Shader.TileMode.MIRROR
)
view.setRenderEffect(blurRenderEffect)
Размытие изображения на Android 12+, преобразованное в растровое изображение
Если вам нужно, чтобы размытое изображение было преобразовано в Bitmap
, платформа поддерживает ускоренный рендеринг с помощью HardwareRenderer
, поддерживаемого HardwareBuffer
. Следующий код создает 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)
Применение эффекта предполагает использование внутреннего RecordingCanvas
для RenderNode
. Следующий код записывает рисунок, создает запрос на отрисовку, а затем ожидает завершения запроса:
val renderCanvas = it.renderNode.beginRecording()
renderCanvas.drawBitmap(it.bitmap, 0f, 0f, null)
renderNode.endRecording()
hardwareRenderer.createRenderRequest()
.setWaitForPresent(true)
.syncAndDraw()
Отрисованное изображение находится в HardwareBuffer
, связанном с ImageReader
. Следующий код получает Image
и возвращает Bitmap
, которое оборачивает его 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")
Следующий код выполняет очистку после рендеринга изображения. Обратите внимание, что ImageReader
, RenderNode
, RenderEffect
и HardwareRenderer
можно использовать для обработки нескольких изображений.
hardwareBuffer.close()
image.close()
imageReader.close()
renderNode.discardDisplayList()
hardwareRenderer.destroy()
AGSL для обработки изображений
Язык шейдинга графики Android (AGSL) используется в Android 13+ для определения поведения программируемых объектов 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;
}
""")
Шейдер можно применить к RenderNode
, как и к любому другому RenderEffect
. В следующем примере показано, как установить униформу в 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
, используется тот же метод, что и в предыдущем примере размытия изображения.
- Внутренний
RecordingCanvas
дляRenderNode
применяет шейдер. -
Image
получается, возвращаяBitmap
, которое обертывает егоHardwareBuffer
.
Преобразование из плоского YUV в RGB с помощью CameraX
Преобразование из плоского YUV в RGB для использования при обработке изображений поддерживается как часть варианта использования ImageAnaанализа в Jetpack's CameraX.
Ресурсы по использованию ImageAnalysis
есть в рамках лаборатории кода «Начало работы с CameraX» и в репозитории образцов камер Android.
Набор инструментов для замены встроенных функций Renderscript
Если ваше приложение использует встроенные функции, вы можете использовать автономную библиотеку замены; наши тесты показывают, что это быстрее, чем использование существующей реализации процессора RenderScript.
В набор инструментов входят следующие функции:
- Смешивать
- Размытие
- Цветовая матрица
- Свернуть
- Гистограмма и гистограммаDot
- Таблица поиска (LUT) и LUT 3D
- Изменить размер
- YUV в RGB
Полную информацию и ограничения см. в файлах README.md
и Toolkit.kt
набора инструментов. файлы.
Выполните следующие шаги, чтобы загрузить, добавить и использовать библиотеку:
Загрузите проект с GitHub.
Найдите и соберите
renderscript-toolkit module
.Добавьте библиотеку в свой проект Android Studio, изменив файл
build.gradle
приложения.Вызовите соответствующий метод набора инструментов.
Пример: миграция из функции ScriptIntrinsicBlur
Чтобы заменить функцию ScriptIntrinsicBlur
:
Чтобы размыть растровое изображение, вызовите
Toolkit.blur
.var blurredBitmap = Toolkit.blur(myBitmap, radius)
Если вы хотите размыть изображение, представленное массивом байтов, укажите ширину, высоту и количество байтов на пиксель.
val outArray = Toolkit.blur(inputArray, bytesPerPixel, width, height, radius)
Миграция со скриптов
Если ваш вариант использования не может быть решен с помощью:
- Набор инструментов для замены RenderScript Intrinsics
- Новые API на платформе Android, такие как
RenderEffect
иAGSL
- API-интерфейсы библиотеки Android Jetpack, такие как
CameraX
И ваш вариант использования может выиграть от ускорения графического процессора: Android поддерживает вычисления графического процессора на кроссплатформенных API-интерфейсах Vulkan и OpenGL ES (GLES). Вам это может показаться ненужным, поскольку на большинстве устройств ваши сценарии уже выполняются на ЦП, а не на графическом процессоре: в некоторых случаях C/C++ может выполнять вычисления быстрее, чем RenderScript, GLES или Vulkan. (или, по крайней мере, достаточно быстро для вашего варианта использования)
Чтобы лучше понять, как выполнить миграцию, просмотрите пример приложения . В примере показано, как размыть растровое изображение и выполнить преобразование цветовой матрицы в RenderScript, а также имеется эквивалентный код в Vulkan и OpenGL.
Если вашему приложению необходимо поддерживать ряд выпусков, используйте RenderScript для устройств под управлением Android 6 (уровень API 23) и ниже, а также Vulkan или GLES на поддерживаемых устройствах с Android 7 (уровень API 24) и выше. Если ваша minSdkVersion
равна 24 или выше, возможно, вам не понадобится использовать RenderScript; Vulkan или GLES 3.1 можно использовать везде, где вам нужна поддержка вычислений на графическом процессоре.
Android предоставляет привязки SDK для API GLES, поэтому нет необходимости использовать NDK при работе в OpenGL ES.
Vulkan не предоставляет привязки SDK, поэтому нет прямого сопоставления RenderScript с Vulkan; вы пишете код Vulkan, используя NDK, и создаете функции JNI для доступа к этому коду из Kotlin или Java.
На следующих страницах рассматриваются аспекты перехода с RenderScript. В примере приложения реализованы почти все эти соображения. Чтобы лучше понять их, сравните эквивалентный код RenderScript и Vulkan.