Skip to content

flyw/librga-android

Repository files navigation

Rockchip RGA (Raster Graphic Acceleration) for Android

This project is an Android build package and Kotlin wrapper for Rockchip's librga (im2d API). It provides hardware-accelerated 2D graphics operations optimized for Rockchip SoCs, including pre-compiled native binaries and an easy-to-use JNI interface.

⚠️ Core Requirement: Why RGA3?

This project forces the use of RGA3 cores for all operations in the JNI layer to ensure reliability on modern Rockchip SoCs.

1. Breaking the 4GB Memory Limit

  • RGA2 Limitation: The RGA2 hardware is primarily designed for a 32-bit addressing space. On Android devices with more than 4GB of RAM, memory allocated by the application layer (like Bitmap or generic physical continuous memory) is likely to reside in high addresses above 4GB.
  • Failure Symptoms: When RGA2 attempts to access these high addresses, it causes address overflow, leading to hardware errors, illegal memory access, or kernel crashes (often seen in dmesg as RGA2 invalid address).
  • RGA3 Advantage: RGA3 cores support 40-bit+ addressing, making them the only reliable choice for hardware acceleration on devices with 8GB, 16GB, or more RAM.
  • Removal of Fill Operation: The hardware fill feature is unique to the RGA2 core. Forcing it to run on RGA3 or using it on high-memory devices would lead to the same 4GB limitation and potential crashes. To ensure system stability, this library has removed the imfill method.

2. Forced RGA3 Scheduling

Each hardware operation (resize, crop, etc.) is now explicitly scheduled to RGA3 cores (Core0 and Core1) within the native JNI implementation. This eliminates the need for manual configuration and prevents unpredictable failures from system defaults.


Features

  • Pre-compiled Binaries: Includes optimized librga.so and librga.a for arm64-v8a and armeabi-v7a.
  • Hardware Acceleration: Full support for Rockchip's RGA hardware engine.
  • Kotlin Wrapper: Clean, idiomatic Kotlin API for image processing.
  • Comprehensive Operations: Support for resize, crop, rotate, flip, blend, and color space conversion (NV21/RGBA/etc.).

Quick Start

0. Running the Demo / Building the Library

By default, the librga module is configured as an Android Application (com.android.application) so you can directly install and run it on a Rockchip device to verify functionality.

To run the test application:

  1. Open the project in Android Studio.
  2. Run the librga configuration.
  3. You will see the RGA JNI Test interface where you can run individual tests (Copy, Resize, Crop, etc.) or all tests at once.

RGA Test App Screenshot

To build the AAR Library:

  1. Open librga/build.gradle.
  2. Change the plugin from com.android.application to com.android.library.
    plugins {
        // id 'com.android.application' // Comment this out
        id 'com.android.library'        // Use this for AAR build
        id 'org.jetbrains.kotlin.android'
    }
  3. Remove or comment out the applicationId in defaultConfig:
    defaultConfig {
        // applicationId "com.rockchip.librga" // Remove for library build
        ...
    }
  4. Run the assemble task:
    ./gradlew :librga:assembleRelease
  5. The AAR will be generated at librga/build/outputs/aar/librga-release.aar.

1. RGA3 Scheduling (Automatic)

The library automatically configures and forces the use of RGA3 cores (Core0 and Core1) for all operations within the native JNI layer. This ensures compatibility with large-memory Android devices and optimal performance without requiring any manual configuration from the developer.

2. Example: Resize Operation

val srcBuffer = Rga.createRgaBufferFromBitmap(srcBitmap)
val dstBuffer = Rga.createRgaBufferFromBitmap(dstBitmap)

// Call hardware resize (automatically uses RGA3)
val result = Rga.imresize(srcBuffer, dstBuffer)

if (result == Rga.IM_STATUS_SUCCESS) {
    Rga.copyRgaBufferToBitmap(dstBuffer, dstBitmap)
}

3. Job/Task System (Batch Processing)

For complex pipelines, use the Job system to batch multiple operations. This is more efficient as it reduces JNI overhead and allows the driver to optimize execution on RGA3.

// 1. Begin a new job
val jobHandle = Rga.imbeginJob()

if (jobHandle > 0) {
    // 2. Add multiple tasks to the job
    // Task 1: Rotate (src -> intermediate)
    Rga.imrotateTask(jobHandle, srcBuffer, intermediateBuffer, Rga.IM_HAL_TRANSFORM_ROT_90)
    
    // Task 2: Vertical Flip (intermediate -> dst)
    Rga.imflipTask(jobHandle, intermediateBuffer, dstBuffer, Rga.IM_HAL_TRANSFORM_FLIP_V)

    // 3. Submit and execute the job
    val result = Rga.imendJob(jobHandle, Rga.IM_SYNC)

    if (result == Rga.IM_STATUS_SUCCESS) {
        Rga.copyRgaBufferToBitmap(dstBuffer, dstBitmap)
    }
}

Project Structure

  • librga/: The core Android Library module.
  • librga/src/main/jniLibs/: Pre-compiled Rockchip RGA native libraries.

Native Build & Packaging

This library uses a hybrid approach for native dependencies to ensure both performance and ease of use:

  • Pre-compiled Binaries: Rockchip's proprietary librga.so and librga.a are stored in jniLibs. These are provided by the SoC vendor and do not have public source code.
  • Source-built JNI: The librga_jni.so (the actual wrapper) is compiled from src/main/cpp/librga_jni.cpp during the Gradle build process. This ensures the wrapper is always in sync with the Kotlin API.
  • Automatic Bundling: When building the project, the Android Gradle Plugin automatically bundles the vendor libraries, the compiled JNI wrapper, and the required libc++_shared.so into the final AAR.

Supported ABIs: arm64-v8a, armeabi-v7a.

Documentation & Source

For the latest RGA documentation, hardware specifications, and the underlying native implementation, please refer to the official Rockchip repository:

👉 Rockchip librga (GitHub)

This Android wrapper is built based on the im2d API provided by the official repository above.

Supported Operations

  • Job / Multi-tasking (Batch Processing)
  • Copy
  • Resize
  • Rescale
  • Crop
  • Rotate
  • Flip
  • Translate
  • Blend
  • Composite
  • Color Format Conversion

API Reference

Constants

// Status codes
const val IM_STATUS_SUCCESS = 1

// Rotation transforms
const val IM_HAL_TRANSFORM_ROT_90     = 1 shl 0
const val IM_HAL_TRANSFORM_ROT_180    = 1 shl 1
const val IM_HAL_TRANSFORM_ROT_270    = 1 shl 2
const val IM_HAL_TRANSFORM_FLIP_H     = 1 shl 3  // Horizontal flip
const val IM_HAL_TRANSFORM_FLIP_V     = 1 shl 4  // Vertical flip
const val IM_HAL_TRANSFORM_FLIP_H_V   = 1 shl 5  // Horizontal and vertical flip

// Blend modes (Porter-Duff)
const val IM_ALPHA_BLEND_SRC_OVER     = 1 shl 6
const val IM_ALPHA_BLEND_SRC          = 1 shl 7
const val IM_ALPHA_BLEND_DST          = 1 shl 8
const val IM_ALPHA_BLEND_SRC_IN       = 1 shl 9
const val IM_ALPHA_BLEND_DST_IN       = 1 shl 10
const val IM_ALPHA_BLEND_SRC_OUT      = 1 shl 11
const val IM_ALPHA_BLEND_DST_OUT      = 1 shl 12
const val IM_ALPHA_BLEND_DST_OVER     = 1 shl 13
const val IM_ALPHA_BLEND_SRC_ATOP     = 1 shl 14
const val IM_ALPHA_BLEND_DST_ATOP     = 1 shl 15
const val IM_ALPHA_BLEND_XOR          = 1 shl 16

// Common pixel formats
const val RK_FORMAT_RGBA_8888 = 0x0
const val RK_FORMAT_RGBX_8888 = 0x1
const val RK_FORMAT_RGB_888 = 0x2
const val RK_FORMAT_BGRA_8888 = 0x3
const val RK_FORMAT_RGB_565 = 0x4
const val RK_FORMAT_RGBA_5551 = 0x5
const val RK_FORMAT_RGBA_4444 = 0x6
const val RK_FORMAT_BGR_888 = 0x7
const val RK_FORMAT_YCbCr_422_SP = 0x8
const val RK_FORMAT_YCbCr_422_P  = 0x9
const val RK_FORMAT_YCbCr_420_SP = 0xa
const val RK_FORMAT_YCbCr_420_P  = 0xb
const val RK_FORMAT_YCrCb_422_SP = 0xc
const val RK_FORMAT_YCrCb_422_P  = 0xd
const val RK_FORMAT_YCrCb_420_SP = 0xe
const val RK_FORMAT_YCrCb_420_P  = 0xf

// Scheduler configuration
const val IM_CONFIG_SCHEDULER_CORE = 0
const val IM_SCHEDULER_RGA3_CORE0 = 1 shl 0
const val IM_SCHEDULER_RGA3_CORE1 = 1 shl 1
const val IM_SCHEDULER_RGA2_CORE0 = 1 shl 2
const val IM_SCHEDULER_RGA2_CORE1 = 1 shl 3

Data Classes

RgaBuffer

Represents an image buffer for RGA operations.

data class RgaBuffer(
    val width: Int,
    val height: Int,
    val format: Int,
    val wstride: Int = width,
    val hstride: Int = height,
    val fd: Int = -1,           // File descriptor (for buffer sharing)
    val handle: Int = 0,        // Buffer handle
    val ptr: ByteBuffer? = null, // Direct ByteBuffer
    val hardwareBuffer: Any? = null // Android HardwareBuffer (API 26+)
)

RgaRect

Defines a rectangular region for cropping and filling operations.

data class RgaRect(
    val x: Int,
    val y: Int,
    val width: Int,
    val height: Int
)

Core RGA Operations

Job Management

external fun imbeginJob(flags: Long = 0): Long
external fun imendJob(jobHandle: Long, syncMode: Int = IM_SYNC): Int
external fun imcancelJob(jobHandle: Long): Int

Copy

Copies source image to destination.

external fun imcopy(src: RgaBuffer, dst: RgaBuffer): Int
external fun imcopyTask(jobHandle: Long, src: RgaBuffer, dst: RgaBuffer): Int

Example:

val srcBuffer = Rga.createRgaBufferFromBitmap(sourceBitmap)
val dstBuffer = Rga.createRgaBufferFromBitmap(destinationBitmap)
val result = Rga.imcopy(srcBuffer, dstBuffer)
// Or use Task API inside a job:
// Rga.imcopyTask(jobHandle, srcBuffer, dstBuffer)

Resize

Resizes source image to destination dimensions.

external fun imresize(src: RgaBuffer, dst: RgaBuffer, fx: Double = 0.0, fy: Double = 0.0): Int
external fun imresizeTask(jobHandle: Long, src: RgaBuffer, dst: RgaBuffer, fx: Double = 0.0, fy: Double = 0.0): Int

Example:

val srcBuffer = Rga.createRgaBufferFromBitmap(sourceBitmap)
val dstBuffer = Rga.createRgaBufferFromBitmap(destinationBitmap)
val result = Rga.imresize(srcBuffer, dstBuffer, 0.5, 0.5) // Scale to 50%

Rescale

Rescales source image to destination dimensions using specific scale factors.

external fun imrescale(src: RgaBuffer, dst: RgaBuffer, fx: Double, fy: Double): Int
external fun imrescaleTask(jobHandle: Long, src: RgaBuffer, dst: RgaBuffer, fx: Double, fy: Double): Int

Example:

val srcBuffer = Rga.createRgaBufferFromBitmap(sourceBitmap)
val dstBuffer = Rga.createRgaBufferFromBitmap(destinationBitmap)
val result = Rga.imrescale(srcBuffer, dstBuffer, 0.5, 0.5) // Scale to 50%

Crop

external fun imcrop(src: RgaBuffer, dst: RgaBuffer, rect: RgaRect): Int
external fun imcropTask(jobHandle: Long, src: RgaBuffer, dst: RgaBuffer, rect: RgaRect): Int

Rotate

external fun imrotate(src: RgaBuffer, dst: RgaBuffer, rotation: Int): Int
external fun imrotateTask(jobHandle: Long, src: RgaBuffer, dst: RgaBuffer, rotation: Int): Int

Flip

external fun imflip(src: RgaBuffer, dst: RgaBuffer, mode: Int): Int
external fun imflipTask(jobHandle: Long, src: RgaBuffer, dst: RgaBuffer, mode: Int): Int

Translate

external fun imtranslate(src: RgaBuffer, dst: RgaBuffer, x: Int, y: Int): Int
external fun imtranslateTask(jobHandle: Long, src: RgaBuffer, dst: RgaBuffer, x: Int, y: Int): Int

Blend

external fun imblend(src: RgaBuffer, dst: RgaBuffer, mode: Int = IM_ALPHA_BLEND_SRC_OVER): Int
external fun imblendTask(jobHandle: Long, src: RgaBuffer, dst: RgaBuffer, mode: Int = IM_ALPHA_BLEND_SRC_OVER): Int

Composite

external fun imcomposite(srcA: RgaBuffer, srcB: RgaBuffer, dst: RgaBuffer, mode: Int = IM_ALPHA_BLEND_SRC_OVER): Int
external fun imcompositeTask(jobHandle: Long, srcA: RgaBuffer, srcB: RgaBuffer, dst: RgaBuffer, mode: Int = IM_ALPHA_BLEND_SRC_OVER): Int

Color Format Conversion

external fun imcvtcolor(src: RgaBuffer, dst: RgaBuffer, sfmt: Int, dfmt: Int): Int
external fun imcvtcolorTask(jobHandle: Long, src: RgaBuffer, dst: RgaBuffer, sfmt: Int, dfmt: Int): Int

Helper Methods

Creating RGA Buffers from Android Bitmap

fun createRgaBufferFromBitmap(bitmap: android.graphics.Bitmap, format: Int = Rga.RK_FORMAT_RGBA_8888): RgaBuffer

Example:

val buffer = Rga.createRgaBufferFromBitmap(bitmap)

Copying RGA Buffer to Android Bitmap

fun copyRgaBufferToBitmap(srcBuffer: RgaBuffer, dstBitmap: android.graphics.Bitmap)

Example:

Rga.copyRgaBufferToBitmap(buffer, bitmap)

Crop Region to Bitmap

Crops a region from an RGA buffer and returns it as a new Bitmap. Handles hardware cropping and format conversion.

fun cropToBitmap(srcBuffer: RgaBuffer, rect: android.graphics.Rect): android.graphics.Bitmap

YUV/NV21 to RGBA Conversion (Hardware Accelerated)

Performs hardware-accelerated color space conversion from NV21/YUV to RGBA.

fun convertNv21ToRgba(srcBuffer: RgaBuffer, dstBuffer: RgaBuffer)

Copy RGBA Buffer to Bitmap

Copies the content of an RGBA RgaBuffer to an Android Bitmap.

fun copyRgbaToBitmap(rgbaBuffer: RgaBuffer, dstBitmap: android.graphics.Bitmap)

Converting Bitmap to ByteBuffer

fun bitmapToByteBuffer(bitmap: android.graphics.Bitmap): java.nio.ByteBuffer

Example:

val byteBuffer = Rga.bitmapToByteBuffer(bitmap)

Creating RGA Buffers from File Descriptor

fun createBufferFromFd(fd: Int, width: Int, height: Int, format: Int, wstride: Int = width, hstride: Int = height): RgaBuffer

Example:

val buffer = Rga.createBufferFromFd(fd, width, height, Rga.RK_FORMAT_RGBA_8888)

Creating RGA Buffers from ByteBuffer

fun createBufferFromByteBuffer(buffer: java.nio.ByteBuffer, width: Int, height: Int, format: Int, wstride: Int = width, hstride: Int = height): RgaBuffer

Example:

val buffer = Rga.createBufferFromByteBuffer(byteBuffer, width, height, Rga.RK_FORMAT_RGBA_8888)

NV21 Data Processing

Creating RGA Buffers from NV21 Data

fun createRgaBufferFromNv21(nv21Data: ByteArray, width: Int, height: Int, format: Int = Rga.RK_FORMAT_YCrCb_420_SP): RgaBuffer

Example:

val buffer = Rga.createRgaBufferFromNv21(nv21ByteArray, width, height)

Filling RGA Buffer with NV21 Data

fun fillRgaBufferWithNv21(buffer: java.nio.ByteBuffer, nv21Data: ByteArray, width: Int, height: Int, format: Int = Rga.RK_FORMAT_YCrCb_420_SP): RgaBuffer

Example:

val buffer = Rga.fillRgaBufferWithNv21(existingByteBuffer, nv21ByteArray, width, height)

Re-packaging Instructions

To re-package this library as a standalone project, follow these steps:

Files to Copy

  1. Root Directory:

    • build.gradle
    • gradle.properties
    • gradlew
    • gradlew.bat
    • settings.gradle
    • .gitignore
  2. Gradle Wrapper Directory:

    • gradle/ (entire directory)
  3. Library Source Directory:

    • librga/ (entire directory)

Step-by-Step Repackaging Process

  1. Create a new directory for your re-packaged project:

    mkdir your-new-project-name
    cd your-new-project-name
  2. Copy the required files from the original project:

    # Copy root files
    cp /path/to/original/project/build.gradle .
    cp /path/to/original/project/gradle.properties .
    cp /path/to/original/project/gradlew .
    cp /path/to/original/project/gradlew.bat .
    cp /path/to/original/project/settings.gradle .
    cp /path/to/original/project/.gitignore .
    
    # Copy gradle wrapper directory
    cp -r /path/to/original/project/gradle/ .
    
    # Copy library directory
    cp -r /path/to/original/project/librga/ .
  3. Update settings.gradle (if needed): Make sure the module is properly included:

    include ':librga'
    rootProject.name = "YourNewProjectName"
  4. Update build.gradle (module level - librga/build.gradle): Adjust the library configuration as needed for your use case:

    android {
        // Update namespace, version, etc. as needed
        namespace 'com.yourcompany.yourlibrary'
        compileSdk 34
    
        defaultConfig {
            minSdk 21
            targetSdk 34
            versionCode 1
            versionName "1.0"
        }
        
        // Other configurations...
    }
  5. Update package names in source files (optional): If you want to change the package name, update:

    • librga/src/main/kotlin/com/rockchip/librga/Rga.kt
    • librga/src/main/kotlin/com/rockchip/librga/TestActivity.kt
    • librga/src/main/AndroidManifest.xml
    • librga/src/main/res/values/strings.xml
  6. Build the project:

    ./gradlew build
  7. Test the library: Create a sample app to verify that the re-packaged library works correctly.

Usage in Your Project

  1. Add the library to your project: Place the librga directory in your project root and include it in your settings.gradle:

    include ':librga'
  2. Add dependency in your app's build.gradle:

    dependencies {
        implementation project(':librga')
    }
  3. Initialize and use the RGA library:

    // The RGA library is automatically initialized when the object is accessed
    val result = Rga.imcopy(srcBuffer, dstBuffer)

License

This project is licensed under the Apache 2.0 License - see the LICENSE file for details.

About

This project is an **Android build package** and Kotlin wrapper for Rockchip's **librga** (im2d API). It provides hardware-accelerated 2D graphics operations optimized for Rockchip SoCs, including pre-compiled native binaries and an easy-to-use JNI interface.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors