Toybrick

RK3399Pro入门教程(5)图形加速引擎RGA的使用

 

jefferyzhang

版主

积分
13610
发表于 2019-4-15 17:48:29    查看: 281517|回复: 99 | [复制链接]    打印 | 显示全部楼层
本帖最后由 jefferyzhang 于 2022-5-27 09:56 编辑


简介

入门教学(1) 中,我们提到了RK自带的RGA核心,可以非常快速的处理二维图像的基本操作,例如
旋转、镜像、缩放、拷贝、剪裁、格式转换等等,那么这篇教学就将详细的说说如何使用。(Android和Linux用法是一致的)


设备节点

RGA的设备节点挂在:
  1. /dev/rga
复制代码


RGA库安装

如果大家不想了解更底层的细节,可以直接安装这个库来使用,我们已经帮大家封装了常用的操作和细节:
  1. sudo apt install rockchip-rga-dev
复制代码


Rockchip封装的LinuxRGA库源码 (new)

  1. https://github.com/rockchip-linux/linux-rga
  2. https://github.com/airockchip/librga
复制代码


如果想进一步了解RGA,可以研究下Android的Hardware/rockchip/librga来查看寄存器的配置等更详细的调用方式,或者使用该代码调用RGA。


示例代码下载地址

本教学的下载地址(已过期):
  1. https://github.com/Jerzha/samples-toybrick-rga.git
复制代码
新RGA教学sample在rga自带目录的sample目录下

注意:
1. sample地址里包含了rockchip_rga目录,该目录的内容就是dnf安装的librockchip_rga内容的源码,如果您不需要修改源码,可以直接dnf安装就好了
2. 如果没有交叉编译环境的话,请放在板子上编译

RGA注意事项

1. 16对齐。所有进入rga的图像的宽高需要进行16对齐,例如1920*1080的图像需要对齐成1920*1088。如果没有显式对齐的话,输出依然会是16对齐的,所以多出几个像素的奇怪的宽高,请不要认为是bug。
2. 可多线程调用来提高利用率
3. 或者设置回调函数的方式提高利用率(库没有提供回调函数注册)
4. RGA自带mmu,可以将虚拟地址转换成物理地址使用(IP核只认识物理地址)。当然如果预先知道物理地址,可以关闭mmu来提升速度。(库没有提供该功能)


基础使用流程(已过期,请参看新RGA Sample

1. 安装RGA库,详见wiki教学

2. 初始化RGA模块,生成context (多线程需要生成多个context)

  1. RockchipRga *mRga;
  2. if (!mRga) {
  3.     printf("create rga failed !\n");
  4.     abort();
  5. }
  6. mRga->ops->initCtx(mRga);
复制代码

3. 设置源(src)和目标(dst)的图片格式、宽高。(需要注意的是,图片格式我们引用Linux V4L2的标准图片格式定义)

  1. mRga->ops->setSrcFormat(mRga, V4L2_PIX_FMT_ABGR32, BUFFER_WIDTH, BUFFER_HEIGHT);
  2. mRga->ops->setDstFormat(mRga, V4L2_PIX_FMT_ABGR32, BUFFER_WIDTH, BUFFER_HEIGHT);
复制代码

4. 设置源(src)和目标(dst)图片的地址。(需要注意的是设置虚拟地址或者fd的接口是不一样的)

  1. mRga->ops->setSrcBufferPtr(mRga, srcBuffer);
  2. mRga->ops->setDstBufferPtr(mRga, dstBuffer);
复制代码

如果是fd(fd一般存在于通过drm申请的buffer), 当然这篇教学里用不到。

  1. mRga->ops->setSrcBufferFd(mRga, srcFd);
  2. mRga->ops->setDstBufferFd(mRga, dstFd);
复制代码

5. 如果只是拷贝和格式转换的话,那做到第四部就可以了。如果还有旋转剪裁等操作,需要再多设置几个:

旋转:
  1. mRga->ops->setRotate(mRga, RGA_ROTATE_90);  // RGA_ROTATE_180, RGA_ROTATE_270
复制代码

剪裁:
  1. mRga->ops->setSrcCrop(mRga, crop_x, crop_y, crop_w, crop_h);
复制代码

(库里提供的就这些。其他功能有需要的话需要自己新增接口了)

6. 插入rga任务队列,开始执行,同步等待返回。

  1. mRga->ops->go(mRga);
复制代码

该函数单个执行其实用不满RGA,因为在设置和返回结果时候RGA是空闲的。这时候可以通过多线程的调用来让RGA不停的排队工作。
或者还有一种更高级的方法就是设置回调函数,给RGA添加任务的时候立即返回,然后等RGA执行完毕后回调告诉程序已经结束,代价当然是程序复杂度就会变得很高。


结果总结

拷贝一张4096*2160的ARGB图像,如果使用malloc的内存(不连续),RGA拷贝速度是比CPU(有cache情况)慢的,测试代码RGA大概需要60ms。实际使用上RGA作为一个流处理器,并且使用CMA连续内容,速度会快非常多,cpu memcpy需要19ms(因为有cache,所以这个代码测试实际上也不能代表问题)如果是DRM分配的物理地址(连续地址)的话,RGA速度是比CPU快很多的,大概在低于15ms(具体数字还需要写代码测试)就可以完成一次搬运。
本篇教学只关注于如果教会大家用RGA,我们就不在这里写drm地址分配的问题了。


RGA优点:
1. 不占用CPU资源
2. DRM/CMA物理内存拷贝和转换速度很快

RGA缺点:
1. 对malloc的不连续的虚拟内存操作速度很慢


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

hjf515

中级会员

积分
213
发表于 2019-4-18 15:38:53 | 显示全部楼层
跑了例程 rga_cpy,发现 checkData 函数中打印出很多dst和src 不一致的数据,这是不是说用 rga copy 有点不可靠。
如果用物理地址,rga cpy是否会更快些,请问在rk3399pro上如何申请物理内存?
物理内存 映射到 虚拟内存,我就可以通过mmap来实现。
回复

使用道具 举报

jefferyzhang

版主

积分
13610
 楼主| 发表于 2019-4-18 16:59:32 | 显示全部楼层
hjf515 发表于 2019-4-18 15:38
跑了例程 rga_cpy,发现 checkData 函数中打印出很多dst和src 不一致的数据,这是不是说用 rga copy 有点不 ...

rga其实就是一个ioctl,填下结构体就可以了,建议你看库源码自己实现一个,或者用android写好的librga库来二次开发。那个不一致是库代码的bug,不是大问题。

物理地址请参看android的libgralloc库来分配,rk的drm留了一些第三方接口来分配CMA/DMA内存,或者你看rga的库里注释掉的代码也是有分配drm内存的方法。
回复

使用道具 举报

盗骊_l

注册会员

积分
66
发表于 2019-7-8 16:15:05 | 显示全部楼层
您好,请问我在Android平台上应该怎么使用 RGA,头文件从哪里来?需要编译什么源码吗?
回复

使用道具 举报

jefferyzhang

版主

积分
13610
 楼主| 发表于 2019-7-9 16:10:26 | 显示全部楼层
盗骊_l 发表于 2019-7-8 16:15
您好,请问我在Android平台上应该怎么使用 RGA,头文件从哪里来?需要编译什么源码吗? ...

android rga查看 device/rockchip/librga
用法不太一样
回复

使用道具 举报

盗骊_l

注册会员

积分
66
发表于 2019-7-9 19:15:38 | 显示全部楼层
jefferyzhang 发表于 2019-7-9 16:10
android rga查看 device/rockchip/librga
用法不太一样

啊?上面不是说  Android和Linux一致吗?
https://github.com/Jerzha/samples-toybrick-rga上面的demo,我编译之后再Android上能正常跑,性能和你上面给出的基本一致。但是我自己写了个function,做格式转换,NV12转rgba,转换处理的rgba数据是错误的。
  1. //格式转换  NV12->ABGR
  2. void rga_convert()
  3. {
  4.     RockchipRga *rga = RgaCreate();

  5.     if (!rga) {
  6.         printf("create rga failed !\n");
  7.         abort();
  8.     }
  9.     rga->ops->initCtx(rga);
  10.     //V4L2_PIX_FMT_NV12  V4L2_PIX_FMT_ABGR32
  11.     rga->ops->setSrcFormat(rga, V4L2_PIX_FMT_NV12, BUFFER_WIDTH, BUFFER_HEIGHT);
  12.     rga->ops->setDstFormat(rga, V4L2_PIX_FMT_ABGR32, BUFFER_WIDTH, BUFFER_HEIGHT);

  13.     rga->ops->setSrcBufferPtr(rga, srcBuffer);
  14.     rga->ops->setDstBufferPtr(rga, dstBuffer);

  15.     rga->ops->go(rga);
  16. }
复制代码
回复

使用道具 举报

jefferyzhang

版主

积分
13610
 楼主| 发表于 2019-7-10 16:39:16 | 显示全部楼层
盗骊_l 发表于 2019-7-9 19:15
啊?上面不是说  Android和Linux一致吗?
https://github.com/Jerzha/samples-toybrick-rga上面的demo, ...

驱动一样,用都可以用。只是android的封装会更高级一点。
你这里的转换代码没有问题,有问题要看看你开的buffer大小是不是对的。
回复

使用道具 举报

15992605143

中级会员

积分
303
发表于 2019-9-6 22:31:28 | 显示全部楼层
rga可以按比例缩放吗?
回复

使用道具 举报

jefferyzhang

版主

积分
13610
 楼主| 发表于 2019-9-8 12:10:11 | 显示全部楼层
15992605143 发表于 2019-9-6 22:31
rga可以按比例缩放吗?

当然可以。但是长宽只能是定点数
回复

使用道具 举报

盗骊_l

注册会员

积分
66
发表于 2019-9-9 13:59:15 | 显示全部楼层
本帖最后由 盗骊_l 于 2019-9-9 14:03 编辑

请问,多线程使用的时候需要注意什么?
我现在遇到的问题:
1>.每个线程里,mpp解码后使用RGA进行格式转换,
  1. RockchipRga *rga = RgaCreate();
复制代码
,初始化一个rga的上下文,一路视频解码后使用RGA转换输出都正常,2路视频解码RGA转换一段时间后,设备重启,3路视频解码,10分钟左右就会造成,设备重启,请问这是什么原因?解码、格式转换结果都正常,就是多路多线程中,一段时间后会造成设备重启。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

产品中心 购买渠道 开源社区 Wiki教程 资料下载 关于Toybrick


快速回复 返回顶部 返回列表