rknn_model_zoo 中的 librga:基于 RGA 2D 硬件加速器的图像处理编程指南
rknn_model_zoo 中的 librga:基于 RGA 2D 硬件加速器的图像处理编程指南
导读
RGA(Raster Graphic Acceleration Unit)是 Rockchip 平台上一颗独立的 2D 硬件加速器,可承担点/线绘制、图像缩放、旋转、bitBlt、alpha 混合等常见 2D 图形操作,将 CPU 从高频的图像搬运与变换中解放出来。本仓库在 3rdparty/librga 目录下内置了 librga —— RGA 的用户空间驱动库及其 2D 图形操作 API(当前版本 v1.10.0),并针对 Android 与 Linux 提供了多种 CPU 架构的预编译产物。阅读本文后,你将掌握 librga 的目录结构、im2d API 分层、核心数据结构与状态码语义,能够在自己的 C/C++ 应用中完成缩放、裁剪、格式转换、旋转、混合、填充等硬件加速操作,并了解它在本仓库 utils/image_utils.c 中的真实调用方式。
librga 在仓库中的定位
根据 3rdparty/librga/README.md 的说明,librga 实现了 RGA 的用户空间驱动,并提供一系列 2D 图形操作 API,其上游来源是 airockchip 维护的 librga 开源项目,当前仓库内置版本为 v1.10.0。该版本号与头文件 im2d_version.h 中的版本定义完全一致:RGA_API_MAJOR_VERSION = 1、RGA_API_MINOR_VERSION = 10、RGA_API_REVISION_VERSION = 0,并可通过 RGA_API_FULL_VERSION 宏在运行时打印完整版本字符串。
在 rknn_model_zoo 的整体架构中,librga 属于 3rdparty 第三方依赖库,与 fftw、jpeg_turbo、opencv、rknpu2 等并列,为上层图像预处理链路(如模型输入图像的缩放、格式转换)提供 2D 硬件加速选项。
目录结构与预编译产物
librga 目录的核心布局如下:
- include/:全部公共头文件,包括 im2d 系列 API 头文件与底层 rga.h;
- Linux/:Linux 平台预编译库,按
aarch64、armhf、armhf_uclibc架构划分,每种架构同时提供librga.a(静态库)与librga.so(动态库); - Android/:Android 平台预编译库,提供
arm64-v8a与armeabi-v7a两套 ABI 的librga.a/librga.so; - README.md:来源与版本说明。
实际开发中可直接链接对应架构的库文件,也可以自行从上游源码构建后替换,使用方式与 OpenCV 等第三方库一致。
头文件体系:im2d API 的分层结构
include 目录下最核心的入口是 im2d.h,它通过简单的 include 组合将整套 API 暴露给使用者:
#include "im2d_version.h"
#include "im2d_type.h"
#include "im2d_common.h"
#include "im2d_buffer.h"
#include "im2d_single.h"
#include "im2d_task.h"
#include "im2d_mpi.h"
各头文件分工明确,可以按功能边界将其划分为五层:
| 头文件 | 职责 |
|---|---|
| im2d_version.h | API 版本宏,用于运行时校验头文件与库的版本匹配 |
| im2d_type.h | 核心类型:缓冲区描述 rga_buffer_t、矩形 im_rect、选项 im_opt_t、枚举 IM_USAGE/IM_STATUS 等 |
| im2d_buffer.h | 缓冲区导入(importbuffer 系列)与包装(wrapbuffer 系列) |
| im2d_single.h | 单任务模式 API:copy/resize/crop/rotate/flip/blend/fill 等 |
| im2d_task.h | 多任务队列模式 API:imbeginJob / imendJob 与各类 xxxTask |
| im2d_common.h | 通用工具:querystring、imStrError、imcheck、imsync、imconfig |
| im2d_mpi.h | 面向 rockit-ko 的上下文(ctx)接口,如 improcess_ctx |
| im2d_expand.h | Android 扩展:GraphicBuffer / AHardwareBuffer 的导入与包装 |
另外 rga.h 属于底层头文件,定义了 RK_FORMAT_* 像素格式枚举,im2d_type.h 会依赖它;RockchipRga.h 则提供较早期的面向对象封装(Rga 类),适合旧代码兼容场景。
核心数据结构与枚举
1. 像素格式:RK_FORMAT_*
RGA 支持 RGB 与 YUV 两大类格式,定义在 rga.h 中(格式值统一左移 8 位以与 Android 的 HAL_PIXEL_FORMAT_* 区分)。常用格式包括:
- RGB 类:
RK_FORMAT_RGBA_8888、RK_FORMAT_RGBX_8888、RK_FORMAT_RGB_888、RK_FORMAT_BGRA_8888、RK_FORMAT_RGB_565、RK_FORMAT_BGR_888; - YUV 半平面/平面类:
RK_FORMAT_YCbCr_420_SP(NV12 风格)、RK_FORMAT_YCrCb_420_SP(NV21 风格)、RK_FORMAT_YCbCr_420_P、RK_FORMAT_YCbCr_422_SP等; - 10 bit 类:
RK_FORMAT_YCbCr_420_SP_10B、RK_FORMAT_YCrCb_420_SP_10B、RK_FORMAT_YCbCr_422_SP_10B等; - 打包格式:
RK_FORMAT_YUYV_422、RK_FORMAT_UYVY_422等。
2. 缓冲区描述:rga_buffer_t
所有 im2d 函数都通过 rga_buffer_t 描述一块图像缓冲区,其定义位于 im2d_type.h:
typedef struct {
void* vir_addr; /* 虚拟地址 */
void* phy_addr; /* 物理地址 */
int fd; /* dma-buf 共享 fd */
int width; /* 图像宽度 */
int height; /* 图像高度 */
int wstride; /* 宽度方向的像素 stride */
int hstride; /* 高度方向的像素 stride */
int format; /* 像素格式,取自 RK_FORMAT_* */
int color_space_mode; /* 色彩空间模式 */
int global_alpha; /* 全局 alpha 值 */
int rd_mode; /* 读取模式(raster/fbc/tile) */
int color; /* 颜色填充时使用的颜色 */
im_colorkey_range colorkey_range;
im_nn_t nn;
int rop_code;
rga_buffer_handle_t handle; /* RGA 驱动中的缓冲区句柄 */
} rga_buffer_t;
注意 wstride/hstride 与 width/height 的区别:前者是缓冲区在内存中实际的对齐 stride,后者是参与运算的可视区域尺寸。对齐不满足硬件要求时,通常需要设置 stride 大于 width。
3. 矩形与选项
im_rect:描述图像上的操作区域,含x、y、width、height四个字段;im_opt_t:单次任务的完整配置项,包含颜色填充值color、colorkey 范围、NN 量化参数nn、ROP 码、调度优先级priority、核心选择core、马赛克模式mosaic_mode、OSD 配置osd_config、中断配置intr_config以及预留字段reserve[128],结构体第一个成员version默认取RGA_CURRENT_API_HEADER_VERSION,用于版本校验。
4. 状态码:IM_STATUS
任何 blit 类函数的返回值都取自 IM_STATUS,其语义定义清晰:
| 状态码 | 值 | 含义 |
|---|---|---|
| IM_STATUS_NOERROR | 2 | 无错误 |
| IM_STATUS_SUCCESS | 1 | 执行成功 |
| IM_STATUS_FAILED | 0 | 执行失败 |
| IM_STATUS_NOT_SUPPORTED | -1 | 不支持该操作/格式组合 |
| IM_STATUS_OUT_OF_MEMORY | -2 | 内存不足 |
| IM_STATUS_INVALID_PARAM | -3 | 参数无效 |
| IM_STATUS_ILLEGAL_PARAM | -4 | 参数非法 |
| IM_STATUS_ERROR_VERSION | -5 | 头文件与库版本不匹配 |
配合 imStrError(status) 宏(定义于 im2d_common.h)可将状态码转换为可读的错误描述字符串,便于调试。
5. 操作位图:IM_USAGE
IM_USAGE 以位图方式描述一次任务要启用的硬件能力(im2d_type.h):
- 几何变换:
IM_HAL_TRANSFORM_ROT_90/180/270、IM_HAL_TRANSFORM_FLIP_H/V; - 混合模式:
IM_ALPHA_BLEND_SRC_OVER(默认 Porter-Duff "SRC over DST")、IM_ALPHA_BLEND_SRC、IM_ALPHA_BLEND_DST、IM_ALPHA_BLEND_SRC_IN、IM_ALPHA_BLEND_DST_IN、IM_ALPHA_BLEND_XOR等; - 高级特性:
IM_ALPHA_COLORKEY_NORMAL/INVERTED(颜色键控)、IM_SYNC/IM_ASYNC(同步/异步)、IM_COLOR_FILL、IM_COLOR_PALETTE、IM_NN_QUANTIZE、IM_ROP、IM_ALPHA_BLEND_PRE_MUL、IM_MOSAIC、IM_OSD等。
此外还有调度核心枚举 IM_SCHEDULER_CORE(可指定 RGA3 Core0/Core1 或 RGA2 Core0)与缩放插值枚举 IM_SCALE_MODE(INTER_NEAREST / INTER_LINEAR / INTER_CUBIC)。
单任务 API:一次调用完成一项操作
单任务模式是最常用的编程方式,每个 API 的典型签名为「输入缓冲 + 输出缓冲 + 操作参数 + 同步标志(默认同步执行)」,全部声明在 im2d_single.h 中。C++ 下使用默认参数即可,C 环境下则通过宏自动展开为 _t 后缀函数并填充默认值。
常用 API 一览:
| API | 功能 | 关键参数 |
|---|---|---|
| imcopy | 图像拷贝 | src、dst、sync |
| imresize | 缩放 | src、dst、fx/fy 缩放因子、interpolation |
| imcrop | 裁剪 | src、dst、im_rect(源图像上的裁剪区域) |
| imtranslate | 平移 | src、dst、目标起始坐标 x/y |
| imcvtcolor | 色彩空间/格式转换 | src、dst、sfmt、dfmt、mode(BT601/BT709 等) |
| imrotate | 旋转 | src、dst、IM_HAL_TRANSFORM_ROT_90/180/270 |
| imflip | 镜像翻转 | src、dst、IM_HAL_TRANSFORM_FLIP_H/V |
| imblend | 双通道混合(前景+背景→背景) | fg、bg、Porter-Duff mode |
| imcomposite | 三通道混合(SRCA+SRCB→DST) | srcA、srcB、dst、mode |
| imcolorkey | 颜色键控 | src、dst、im_colorkey_range、mode |
| imquantize | NN 量化 | src、dst、im_nn_t(各通道 scale/offset) |
| imfill / imfillArray | 颜色填充 | dst、im_rect、color |
| imrectangle | 画矩形框 | dst、rect、color、thickness(负值=实心) |
| immosaic | 马赛克 | image、rect、IM_MOSAIC_8/16/32/64/128 |
| impalette | 调色板/LUT 映射 | src、dst、lut |
| improcess | 通用单任务处理 | src/dst/pat 三通道 + 三个矩形 + im_opt_t + usage |
| immakeBorder | 扩边 | src、dst、top/bottom/left/right、border_type、value |
以缩放入口为例,C++ 接口签名为:
IM_API IM_STATUS imresize(const rga_buffer_t src, rga_buffer_t dst,
double fx = 0, double fy = 0,
int interpolation = 0, int sync = 1,
int *release_fence_fd = NULL);
当 sync == 1 时函数阻塞等待任务完成并直接返回状态码;当 sync == 0 时异步提交,通过 release_fence_fd 输出用于查询任务状态的 fence fd,之后可配合 imsync(release_fence_fd) 等待完成,适合流水线并行场景。
任务队列 API:一次提交多个操作
当需要对同一批图像连续执行多个操作(如先裁剪再缩放再格式转换)时,可以使用任务模式(im2d_task.h)将多个 task 打包成一个 RGA job 一次性提交,减少用户态与内核态的往返开销。基本流程为:
im_job_handle_t job = imbeginJob(); // 创建 job
imcropTask(job, src, tmp, rect); // 加入裁剪任务
imresizeTask(job, tmp, dst, 0, 0, INTER_LINEAR); // 加入缩放任务
imcvtcolorTask(job, tmp, dst, sfmt, dfmt); // 加入格式转换任务
IM_STATUS ret = imendJob(job); // 提交并执行(默认 IM_SYNC)
核心接口包括:
imbeginJob(uint64_t flags = 0):创建 job,返回im_job_handle_t句柄;imendJob(job, sync_mode = IM_SYNC, acquire_fence_fd = 0, int *release_fence_fd = NULL):提交 job,支持同步/异步两种运行模式;imcancelJob(job):取消并销毁 job;- 各类
imxxxTask(job, ...):向 job 追加任务,包括 imcopyTask、imresizeTask、imcropTask、imrotateTask、imflipTask、imblendTask、imcompositeTask、imfillTask、immosaicTask、impaletteTask、improcessTask 等,与单任务 API 一一对应。
任务模式的任务全部在硬件端串行/流水执行,可避免中间结果的多次内存搬运,适合对性能敏感的预处理链路。
缓冲区管理:importbuffer 与 wrapbuffer
RGA 硬件不能直接访问普通 malloc 内存,因此 im2d 提供了两套缓冲区接口(im2d_buffer.h):
导入(importbuffer)——把外部分配的缓冲区注册到 RGA 驱动,返回 rga_buffer_handle_t 句柄:
importbuffer_fd(int fd, ...):传入 dma-buf 的 fd(推荐方式,drm 分配);importbuffer_virtualaddr(void *va, ...):传入虚拟地址(需映射为连续物理内存场景);importbuffer_physicaladdr(uint64_t pa, ...):传入物理地址;releasebuffer_handle(handle):任务结束后释放句柄。
导入接口存在三组重载:仅传 size、传 width/height/format、或传 im_handle_param_t 结构体(内含 width、height、format 三字段)。
包装(wrapbuffer)——把已导入的句柄或内存描述包装成 rga_buffer_t:
wrapbuffer_handle(handle, width, height, format, ...):基于句柄包装;wrapbuffer_virtualaddr / wrapbuffer_physicaladdr / wrapbuffer_fd:基于地址/fd 直接包装(此时无需先 importbuffer);- 可选的第 4、5 个参数为
wstride、hstride,省略时默认wstride = width、hstride = height。
典型使用模式:
rga_buffer_handle_t hnd = importbuffer_fd(dma_fd, width, height, fmt);
rga_buffer_t src = wrapbuffer_handle(hnd, width, height, fmt, wstride, hstride);
// ... 执行 im2d 操作 ...
releasebuffer_handle(hnd);
在 Android 平台上,im2d_expand.h 还提供了 importbuffer_GraphicBuffer、wrapbuffer_AHardwareBuffer 等扩展接口,可直接对接 Android 图形缓冲区。
通用工具:能力查询与参数校验
im2d_common.h 提供一组与具体操作无关的辅助接口:
querystring(RGA_VENDOR / RGA_VERSION / RGA_MAX_INPUT / RGA_MAX_OUTPUT / RGA_INPUT_FORMAT / RGA_OUTPUT_FORMAT / RGA_EXPECTED / RGA_ALL):查询 RGA 硬件的基本信息、支持的最大分辨率与格式集合,返回描述字符串;imStrError(IM_STATUS):将状态码转为错误信息字符串;imcheckHeader():校验头文件版本与库版本是否一致,避免因 API 不匹配导致未定义行为;imcheck(src, dst, src_rect, dst_rect, mode_usage):在提交任务前检查输入输出缓冲、区域与 usage 是否被当前硬件支持,返回IM_STATUS_NOERROR表示可执行;imconfig(IM_CONFIG_NAME, value):配置调度核心、优先级等全局行为;imsync(int release_fence_fd):阻塞等待指定 fence fd 对应的任务完成。
建议在正式业务代码前先调用 imcheckHeader(),并在每次任务后检查返回值,这是 librga 编程中保证稳定性的基本实践。
在 rknn_model_zoo 中的真实应用
本仓库的 utils/image_utils.c 在实现图像预处理/后处理时提供了基于 librga 的加速路径:文件第 7 行直接 #include "im2d.h",随后根据缓冲区来源(物理地址 / dma fd / 虚拟地址)分别调用 importbuffer_physicaladdr、importbuffer_fd、importbuffer_virtualaddr 导入源/目标缓冲区(源码第 585-613 行),再通过 wrapbuffer_handle / wrapbuffer_physicaladdr / wrapbuffer_fd / wrapbuffer_virtualaddr 包装出 rga_buffer_t 参与后续处理(源码第 596-627 行)。这一实现是 librga 接口在真实工程中的典型范例,展示了「导入 → 包装 → 执行 → 释放」的完整调用链,可作为开发者将 RGA 加速引入自研预处理管线的参考模板。
平台适配与集成建议
根据预编译产物目录,librga 覆盖的部署环境包括:
- Linux:aarch64、armhf、armhf_uclibc(静态库与动态库);
- Android:arm64-v8a、armeabi-v7a。
集成时需注意三点:其一,RGA 是 Rockchip SoC 上的硬件单元,librga 只能运行于具备 RGA 硬件(如 RK356x/RK3588 等系列)的目标板上,x86 宿主机无法直接使用;其二,使用前确认内核已加载 rga 驱动节点;其三,头文件版本与库版本需保持一致,可使用 imcheckHeader() 或 RGA_API_FULL_VERSION 宏在运行时校验。对于本仓库的模型推理场景,当输入图像尺寸与模型输入不一致、或需要将相机帧(通常为 YUV)转换为模型所需的 RGB 布局时,都可以借助 imresize + imcvtcolor 的组合把预处理卸载到 RGA 上,降低 CPU 占用与整体延迟。
小结
librga 通过一套分层清晰的 im2d API,把 Rockchip RGA 2D 硬件加速器的能力以「缓冲区 + 单任务/任务队列」两种模式暴露给应用层:rga_buffer_t 描述图像,IM_USAGE 声明能力,IM_STATUS 汇报结果,importbuffer/wrapbuffer 负责内存对接。结合本仓库 3rdparty/librga 内置的 v1.10.0 头文件与多架构预编译库,以及 utils/image_utils.c 的实践范例,开发者可以快速在 Rockchip 平台上构建出高性能的图像缩放、格式转换、旋转与混合流水线。