RK3588S带了一个RGA3,其本质上是一个2D图形变换加速器,能够支持典型的2D图像变换处理,如伸缩,合并,水印叠加等。最大支持分辨率为8192x8192的图像处理。
由于风火轮科技已经开源了sdk,因此建议在PC端的SDK进行统一构建,这样可以保证构建环境一致。SDK里面自带的交叉编译环境和板上的环境是一致的。
RGA库源码目前只能从SDK获取,可以拉取风火轮科技提供的整个SDK。RGA源码在SDK根目录的
external/linux-rga
下,建议将这个源码拷贝到一个单独的工作目录使用
如果不想下载整个SDK的,可以从下方链接下载linux-rga的包
首先配置交叉编译环境。在 SDK根目录 下,执行下面几行内容
DIR=$(pwd)
export PATH=$PATH:${DIR}/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin
export CROSS_COMPILE=aarch64-none-linux-gnu-
export ARCH=aarch64
在rga的工作目录下,打开 toolchains 目录
然后修改 toolchain_linux.cmake 文件中编译器目录,如下
# 这里的XXX换成 SDK 的路径
SET(TOOLCHAIN_HOME "XXX/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu")
然后在 rga工作目录 下执行
./cmake-linux.sh
即可执行编译,编译完成的信息如下
编译完成后,可以在build/build_linux目录下看到如下文件
其中librga.a为静态库 librga.so为动态库 samples/im2d_api_demo下有个rgaImDemo为测试demo
将上步骤生成的rgaImDemo文件放到板上。首先验证板上的环境是否正确,直接执行
./rgaImDemo --querystring
如果看到下面的结果,说明板上环境没问题。
找一个测试图片,这个图片需要是1280x720,格式为rgba8888的,在samples/sample_file
里面有两个,这里使用in1w1280-h720-rgba8888.bin。在PC端可以使用YUView来查看RAW格式的图像。在YUView可以看到其内容如下
将其放到板上的/usr/data/目录下,并重命名为in0w1280-h720-rgba8888.bin
root@linaro-alip:~# ls -ll /usr/data
总用量 3600
-rw-rw-rw- 1 root root 3686400 11月 26 2023 in0w1280-h720-rgba8888.bin
然后测试一下图像的缩放和旋转变换,这两个也是RGA里面最常用的功能
# 放大为720p
root@linaro-alip:~# ./rgaImDemo --resize up
Start selecting mode 0
im2d resize ..
up resize ...
MODE = 2
open file
rga_api version 1.8.1_[3]
resizing .... cost time 3927 us, Run successfully
open /usr/data/out0w1920-h1080-rgba8888.bin and write ok
root@linaro-alip:~#
root@linaro-alip:~#
# 缩小为480p
root@linaro-alip:~# ./rgaImDemo --resize down
Start selecting mode 0
im2d resize ..
down resize ...
MODE = 2
open file
rga_api version 1.8.1_[3]
resizing .... cost time 2429 us, Run successfully
open /usr/data/out0w720-h480-rgba8888.bin and write ok
root@linaro-alip:~#
root@linaro-alip:~#
root@linaro-alip:~#
# 旋转90度
root@linaro-alip:~# ./rgaImDemo --rotate 90
Start selecting mode 0
im2d rotate ..
rotation 90 ...
MODE = 4
open file
rga_api version 1.8.1_[3]
rotating .... cost time 3192 us, Run successfully
open /usr/data/out0w720-h1280-rgba8888.bin and write ok
然后将生成的3个文件放到PC端的YUView上查看
下面以demo中的im2d_api_demo源码为例,介绍一下rga动态库的使用方法。
此源文件位置在linux-rga工程的samples目录下
首先看下main函数,它首先使用 readArguments 解析出了所有的参数,然后根据参数类型,进行不同的动作
int main(int argc, char* argv[]) {
int ret = 0, while_time = 0;
int parm_data[MODE_MAX] = {0};
int COLOR;
IM_USAGE ROTATE;
IM_USAGE FLIP;
int MODE;
IM_INFORMATION IM_INFO;
IM_STATUS STATUS;
im_rect src_rect;
im_rect dst_rect;
rga_buffer_t src;
rga_buffer_t dst;
rga_buffer_handle_t src_handle;
rga_buffer_handle_t dst_handle;
char* src_buf = NULL;
char* dst_buf = NULL;
memset(&src_rect, 0, sizeof(src_rect));
memset(&dst_rect, 0, sizeof(dst_rect));
memset(&src, 0, sizeof(src));
memset(&dst, 0, sizeof(dst));
MODE = readArguments(argc, argv, parm_data);
...
/********** Get parameters **********/
if(MODE != MODE_QUERYSTRING) {
src_buf = (char*)malloc(SRC_WIDTH*SRC_HEIGHT*get_bpp_from_format(SRC_FORMAT));
dst_buf = (char*)malloc(DST_WIDTH*DST_HEIGHT*get_bpp_from_format(DST_FORMAT));
ret = get_buf_from_file(src_buf, SRC_FORMAT, SRC_WIDTH, SRC_HEIGHT, 0);
...
if(MODE == MODE_BLEND || MODE == MODE_FILL) {
ret = get_buf_from_file(dst_buf, DST_FORMAT, DST_WIDTH, DST_HEIGHT, 1);
...
} else {
memset(dst_buf,0x00,DST_WIDTH*DST_HEIGHT*get_bpp_from_format(DST_FORMAT));
}
src_handle = importbuffer_virtualaddr(src_buf, SRC_WIDTH, SRC_HEIGHT, SRC_FORMAT);
...
dst_handle = importbuffer_virtualaddr(dst_buf, DST_WIDTH, DST_HEIGHT, DST_FORMAT);
...
src = wrapbuffer_handle(src_handle, SRC_WIDTH, SRC_HEIGHT, SRC_FORMAT);
dst = wrapbuffer_handle(dst_handle, DST_WIDTH, DST_HEIGHT, DST_FORMAT);
...
}
do {
...
switch(MODE) {
case MODE_QUERYSTRING :
IM_INFO = (IM_INFORMATION)parm_data[MODE_QUERYSTRING];
printf("\n%s\n", querystring(IM_INFO));
break;
case MODE_COPY : //rgaImDemo --copy
ret = imcheck(src, dst, src_rect, dst_rect);
...
STATUS = imcopy(src, dst);
...
break;
case MODE_RESIZE : //rgaImDemo --resize=up/down
releasebuffer_handle(dst_handle);
dst_handle = -1;
switch(parm_data[MODE_RESIZE]) {
case IM_UP_SCALE :
if (dst_buf != NULL) {
free(dst_buf);
dst_buf = NULL;
}
dst_buf = (char*)malloc(1920*1080*get_bpp_from_format(DST_FORMAT));
...
memset(dst_buf,0x00,1920*1080*get_bpp_from_format(DST_FORMAT));
dst_handle = importbuffer_virtualaddr(dst_buf, 1920, 1080, DST_FORMAT);
...
dst = wrapbuffer_handle(dst_handle, 1920, 1080, DST_FORMAT);
...
break;
case IM_DOWN_SCALE :
if (dst_buf != NULL) {
free(dst_buf);
dst_buf = NULL;
}
dst_buf = (char*)malloc(720*480*get_bpp_from_format(DST_FORMAT));
memset(dst_buf,0x00,720*480*get_bpp_from_format(DST_FORMAT));
dst_handle = importbuffer_virtualaddr(dst_buf, 720, 480, DST_FORMAT);
...
dst = wrapbuffer_handle(dst_handle, 720, 480, DST_FORMAT);
...
break;
}
ret = imcheck(src, dst, src_rect, dst_rect);
...
STATUS = imresize(src, dst);
break;
case MODE_CROP : //rgaImDemo --crop
src_rect.x = 100;
src_rect.y = 100;
src_rect.width = 300;
src_rect.height = 300;
ret = imcheck(src, dst, src_rect, dst_rect, IM_CROP);
...
STATUS = imcrop(src, dst, src_rect);
...
break;
case MODE_ROTATE : //rgaImDemo --rotate=90/180/270
ROTATE = (IM_USAGE)parm_data[MODE_ROTATE];
if (IM_HAL_TRANSFORM_ROT_90 == ROTATE || IM_HAL_TRANSFORM_ROT_270 == ROTATE) {
dst.width = src.height;
dst.height = src.width;
dst.wstride = src.hstride;
dst.hstride = src.wstride;
}
ret = imcheck(src, dst, src_rect, dst_rect, ROTATE);
...
STATUS = imrotate(src, dst, ROTATE);
...
break;
case MODE_FLIP : //rgaImDemo --flip=H/V
FLIP = (IM_USAGE)parm_data[MODE_FLIP];
ret = imcheck(src, dst, src_rect, dst_rect);
...
STATUS = imflip(src, dst, FLIP);
...
break;
case MODE_TRANSLATE : //rgaImDemo --translate
src_rect.x = 300;
src_rect.y = 300;
ret = imcheck(src, dst, src_rect, dst_rect);
...
STATUS = imtranslate(src, dst, src_rect.x, src_rect.y);
...
break;
case MODE_BLEND : //rgaImDemo --blend
ret = imcheck(src, dst, src_rect, dst_rect);
...
STATUS = imblend(src, dst);
...
break;
case MODE_CVTCOLOR : //rgaImDemo --cvtcolor
src.format = RK_FORMAT_RGBA_8888;
dst.format = RK_FORMAT_YCbCr_420_SP;
...
ret = imcheck(src, dst, src_rect, dst_rect);
...
STATUS = imcvtcolor(src, dst, src.format, dst.format);
...
break;
case MODE_FILL : //rgaImDemo --fill=blue/green/red
COLOR = parm_data[MODE_FILL];
dst_rect.x = 100;
dst_rect.y = 100;
dst_rect.width = 300;
dst_rect.height = 300;
ret = imcheck(src, dst, src_rect, dst_rect, IM_COLOR_FILL);
...
STATUS = imfill(dst, dst_rect, COLOR);
...
break;
...
}
...
/********** release rga buffer handle **********/
releasebuffer_handle(src_handle);
releasebuffer_handle(dst_handle);
/********** output buf data to file **********/
if (src_buf != NULL) {
free(src_buf);
src_buf = NULL;
}
if (dst_buf != NULL) {
output_buf_data_to_file(dst_buf, dst.format, dst.wstride, dst.hstride, 0);
free(dst_buf);
dst_buf = NULL;
}
return 0;
}
然后每一种case的处理是先调用imcheck校验参数是否合法,以及当前硬件是否支持该操作
然后调用不同的处理,比如
imcopy是执行单次快速图像拷贝操作,将图像从src通道图像缓冲区拷贝到dst通道图像缓冲区上
imresize是图像缩放
imcrop是图像裁剪
imrotate是图像旋转
整体来看,RK的RGA库API调用起来还是比较简单的,demo工程也比较清晰。
具体的RGA 的API可以参考RGA说明文档,在docs/cn/Common/RGA/Rockchip_Developer_Guide_RGA_CN.pdf里面。