RenderScript APIs are deprecated starting in Android 12. Device and component manufacturers have already stopped providing hardware acceleration support, and RenderScript support is expected to be removed entirely in a future release.

C/C++ performance may be adequate for many use cases, and if you were only reliant on RenderScript for intrinsics, you can replace those uses with the[RenderScript Intrinsics Replacement Toolkit](https://developer.android.com/guide/topics/renderscript/migrate#intrinsics), which is easier to use and comes with a potential 2x performance improvement!

If you need to take full advantage of GPU acceleration, we recommend[migrating your scripts to Vulkan](https://developer.android.com/guide/topics/renderscript/migrate/migrate-vulkan), Other accelerated options include[migrating your scripts to OpenGL](https://developer.android.com/guide/topics/renderscript/migrate/migrate-gles), using[Canvas-based image operations](https://developer.android.com/guide/topics/renderscript/migrate#built-in), or leveraging the[Android Graphics Shading Language (AGSL)](https://developer.android.com/guide/topics/renderscript/migrate#AGSL-processing).

Following the deprecation of RenderScript in the Android platform, support for RenderScript is being removed in the Android Gradle plugin. Starting with Android Gradle plugin 7.2, the RenderScript APIs are deprecated. They continue to function, but invoke warnings. Future versions of AGP will no longer include Renderscript support. This guide explains how to migrate from RenderScript.

## Migrate from intrinsics

Although the RenderScript intrinsics functions continue to function after the RenderScript deprecation, they may execute only on the CPU rather than the GPU.

For some of these operations, there are more efficient options now built into the platform or in Jetpack libraries.

### Built-in accelerated image operations

The Android platform supports accelerated image processing operations that can be applied to images, independent of RenderScript intrinsics. Examples include:

- Blend
- Blur
- Color Matrix
- Resize

#### Image blur on Android 12+ into a View

[`RenderEffect`](https://developer.android.com/reference/android/graphics/RenderEffect "RenderEffect")with support for blur was added into Android 12, API level 31, allowing you to blur a[`RenderNode`](https://developer.android.com/reference/android/graphics/RenderNode "RenderNode").`RenderNode`is a construct of the display list that Android uses to help accelerate platform graphics.

Android provides a shortcut to applying an effect to the`RenderNode`associated with a`View`. To blur a`View`, call[`View.setRenderEffect()`](https://developer.android.com/reference/android/view/View#setRenderEffect(android.graphics.RenderEffect) "setRenderEffect"):  

    val blurRenderEffect = RenderEffect.createBlurEffect(radius, radius,
            Shader.TileMode.MIRROR
        )
    view.setRenderEffect(blurRenderEffect)

#### Image blur on Android 12+ rendered into a Bitmap

If you need the blurred image rendered into a`Bitmap`, the framework supports accelerated rendering with a[`HardwareRenderer`](https://developer.android.com/reference/android/graphics/HardwareRenderer "HardwareRenderer")backed by a[`HardwareBuffer`](https://developer.android.com/reference/android/hardware/HardwareBuffer "HardwareBuffer"). The following code creates the`HardwareRenderer`,`RenderNode`, and the`RenderEffect`for the blur:  

    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)

Applying the effect involves using the internal[`RecordingCanvas`](https://developer.android.com/reference/android/graphics/RecordingCanvas "RecordingCanvas")for the`RenderNode`. The following code records the drawing, creates the render request, and then waits for the request to finish:  

    val renderCanvas = it.renderNode.beginRecording()
    renderCanvas.drawBitmap(it.bitmap, 0f, 0f, null)
    renderNode.endRecording()
    hardwareRenderer.createRenderRequest()
        .setWaitForPresent(true)
        .syncAndDraw()

The rendered image is in a[`HardwareBuffer`](https://developer.android.com/reference/android/hardware/HardwareBuffer "HardwareBuffer")associated with the[`ImageReader`](https://developer.android.com/reference/android/media/ImageReader "ImageReader"). The following code acquires the`Image`and returns a`Bitmap`that wraps its`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")

The following code cleans-up after rendering the image. Note that the`ImageReader`,`RenderNode`,`RenderEffect`, and`HardwareRenderer`can be used to process multiple images.  

    hardwareBuffer.close()
    image.close()
    imageReader.close()
    renderNode.discardDisplayList()
    hardwareRenderer.destroy()

#### AGSL for image processing

The[Android Graphics Shading Language (AGSL)](https://developer.android.com/develop/ui/views/graphics/agsl)is used by Android 13+ to define the behavior of programmable[`RuntimeShader`](https://developer.android.com/reference/android/graphics/RuntimeShader)objects. AGSL shares much of its syntax with GLSL fragment shaders, but works within the Android graphics rendering system to both customize painting within`Canvas`and filter`View`content. This can be used to add custom image processing during drawing operations, or by using a`RenderNode`directly to render an image into a`Bitmap`canvas. The following example demonstrates how to apply a custom shader to replace the image blur effect.

Begin by creating a`RuntimeShader`, instantiating it with the AGSL shader code. This shader is used to apply a color matrix for hue rotation:  

    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;
        }
    """)

The shader can be applied to a`RenderNode`, just like any other`RenderEffect`. The following example demonstrates how to set the uniforms in the 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)

To get the`Bitmap`, the same technique is used as in the previous image blur sample.

- The internal[`RecordingCanvas`](https://developer.android.com/reference/android/graphics/RecordingCanvas "RecordingCanvas")for the`RenderNode`applies the shader.
- The`Image`is acquired, returning a`Bitmap`that wraps its`HardwareBuffer`.

### Convert from planar YUV to RGB using CameraX

Converting from[planar YUV](https://developer.android.com/reference/android/graphics/ImageFormat#YUV_420_888)to RGB for use in image processing is supported as part of the[ImageAnalysis](https://developer.android.com/training/camerax/analyze)use case within Jetpack's CameraX.

There are resources on using`ImageAnalysis`as part of the[Getting Started with CameraX](https://developer.android.com/codelabs/camerax-getting-started)codelab and in the Android camera[samples](https://github.com/android/camera-samples/)repository.

### The Renderscript intrinsics replacement toolkit

If your application uses intrinsics, you can use the standalone replacement library; our tests indicate it's faster than using the existing RenderScript CPU implementation.

The toolkit includes the following functions:

- Blend
- Blur
- Color matrix
- Convolve
- Histogram and histogramDot
- Lookup table (LUT) and LUT 3D
- Resize
- YUV to RGB

For full details and limitations, see the toolkit's[`README.md`](https://github.com/android/renderscript-intrinsics-replacement-toolkit/blob/main/README.md)and[`Toolkit.kt`](https://github.com/android/renderscript-intrinsics-replacement-toolkit/blob/main/renderscript-toolkit/src/main/java/com/google/android/renderscript/Toolkit.kt). files.

Perform the following steps to download, add, and use the library:

1. Download the[project](https://github.com/android/renderscript-intrinsics-replacement-toolkit)from GitHub.

2. Locate and build the`renderscript-toolkit module`.

   | **Note:** If you'd like to run the intrinsics on the GPU instead, refer to the examples of coding blur and color matrix in[Vulkan](https://developer.android.com/guide/topics/renderscript/migrate/migrate-vulkan)or[OpenGL ES](https://developer.android.com/guide/topics/renderscript/migrate/migrate-gles).
3. Add the library to your Android Studio project by modifying the app's`build.gradle`file.

4. Invoke the appropriate method of the toolkit.

### Example: migrate from the ScriptIntrinsicBlur function

To replace the`ScriptIntrinsicBlur`function:

- To blur a bitmap, call`Toolkit.blur`.

      var blurredBitmap = Toolkit.blur(myBitmap, radius)

- If you want to blur an image represented by an array of bytes, specify the width, height, and the number of bytes per pixel.

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

| **Note:** Check the toolkit documentation for the latest guidance.

## Migrate from scripts

If your use case cannot be solved with:

- The[RenderScript Intrinsics Replacement Toolkit](https://developer.android.com/guide/topics/renderscript/migrate#intrinsics)
- New APIs within the Android platform such as`RenderEffect`and`AGSL`
- Android Jetpack library APIs such as`CameraX`

And, your use case can benefit from GPU acceleration, Android supports GPU compute on cross-platform Vulkan and OpenGL ES (GLES) APIs. You may find this unnecessary because on most devices your scripts are already running on the CPU instead of the GPU: C/C++ may be faster than RenderScript, GLES, or Vulkan compute for some use cases. (or at least fast enough for your use case)

To better understand how to migrate, review the[sample app](https://github.com/android/renderscript-samples/tree/main/RenderScriptMigrationSample/). The sample demonstrates how to both blur a bitmap and do a color-matrix conversion in RenderScript, and has equivalent code in Vulkan and OpenGL.

If your application needs to support a range of releases, use RenderScript for devices running Android 6 (API level 23) and lower, and Vulkan or GLES on supported devices with Android 7 (API level 24) and higher. If your`minSdkVersion`is 24 or higher, you may not need to use RenderScript; Vulkan or GLES 3.1 can be used anywhere you need GPU compute support.
| **Note:** RenderScript provides support for CPU compute on devices that don't have GPU compute support.

Android provides SDK bindings for GLES APIs, so it is not necessary to use the NDK when working in OpenGL ES.

Vulkan doesn't provide SDK bindings, so there is no direct mapping from RenderScript to Vulkan; you write the Vulkan code using the NDK and create JNI functions to access this code from Kotlin or Java.

The following pages cover aspects of migrating from RenderScript. The sample app implements almost all of these considerations. To better understand them, compare the RenderScript and Vulkan equivalent code.

- [Migrate scripts to OpenGL ES 3.1](https://developer.android.com/guide/topics/renderscript/migrate/migrate-gles)
- [Migrate scripts to Vulkan](https://developer.android.com/guide/topics/renderscript/migrate/migrate-vulkan)