RGA(一)——基础知识

一、RGA 到底是什么?

RGA 的全称是 Raster Graphic Acceleration Unit,翻译过来就是"光栅图形加速单元"。

官方的定义是这样的:

RGA 是一个独立的 2D 硬件加速器,可用于加速点/线绘制,执行图像缩放、旋转、bitBlt、alpha 混合等常见的 2D 图形操作。

翻译成小白能懂的话:RGA 就是一块专门用来处理图像的硬件电路。它独立于 CPU、GPU、VPU 之外,专门干这些活:

  • 图像缩放,也就是放大和缩小
  • 图像旋转 90 度、180 度、270 度
  • 图像镜像翻转,水平翻或者垂直翻
  • 图像裁剪,从大图里抠出一块
  • 图像拷贝,也就是 bitBlt
  • 图像叠加,比如叠字幕、叠水印,官方叫 alpha blend
  • 图像格式转换,比如 YUV 转 RGB,官方叫 CSC
  • 画点、画线、画框、填充颜色
  • 抠图,官方叫 Color Key
  • 光栅运算,AND、OR、XOR 这些
  • 马赛克遮盖
  • OSD 字幕叠加

基本上你能想到的"对一帧画面做几何或像素层面的变换",它都能干。


二、关键点:它是"独立"的

官方特别强调了"独立"这两个字:

关键点在于"独立":它不和 CPU 抢 ALU,不和 GPU 抢着色器,也不阻塞 VPU 编解码。它是一条专用的、吞吐固定的像素流水线。

拆开看:

不抢 CPU 的 ALU。 ALU 是算术逻辑单元,CPU 算加减乘除、逻辑运算都靠它。RGA 不占用这部分资源。

不抢 GPU 的着色器。 UI 渲染、3D 绘制用的 GPU Shader,RGA 也不碰。

不阻塞 VPU 编解码。 VPU 是视频编解码硬件,MPP 用的就是它。RGA 和它是两条独立的流水线。

为什么"独立"这么重要?

假设你要做一个视频播放器,把一帧 1920×1080 的 NV12 图像缩放到 1280×720,再转成 RGB888 送给屏幕。不用 RGA 的话有三个选择:

让 CPU 用 libyuv 或 swscale 逐像素算。 1080p 一帧约 300 万像素,每秒 30 帧就是 9000 万次像素操作,还要做 YUV 到 RGB 的定点或浮点运算。CPU 直接被占满。

让 GPU 用 shader 算。 GPU 同时在跑 UI 渲染,两者抢资源,UI 可能会卡。

让 VPU 顺带做。 VPU 的主职是视频编解码,不擅长这类通用图像变换。

用了 RGA 之后: CPU 只负责下命令,告诉 RGA 源图像在哪、目标图像在哪、要做什么操作,RGA 硬件自己去搬数据、算结果、写回去。CPU 几乎不参与像素搬运。

这就是官方那句话的含义:把 CPU 从像素搬运里解放出来。

但有一点要注意:它会抢 DDR 带宽

RGA 虽然不抢 CPU、GPU、VPU 的计算资源,但它读写图像数据还是要走 DDR 内存。官方 FAQ 里有一句话很关键:

因为 RGA 在目前 RK 平台中的总线优先级为最低档,当带宽资源较为紧张时,例如 ISP 运行多路的场景中,RGA 由于带宽资源紧张,没有办法及时的读写 DDR 内的数据,产生了较大的延迟,从而表现为 RGA 的性能下降。

翻译一下:如果系统里 ISP、VPU 这些模块把内存带宽占满了,RGA 会被拖慢,因为它的总线优先级是最低档。后面讲性能时会重点展开。


三、RGA 在整个系统里站在哪?

RK 平台的多媒体栈大概长这样:

objectivec 复制代码
vpu_service   →   mpp   →   gstreamer / rockit   →   app
 │               │               │                  │
 │               │               │                  └─ 你的业务代码
 │               │               └─ 对接 app 的中间件
 │               └─ 视频编解码中间件:MPP
 └─ 内核驱动:vdpu / vepu / rkvdec / rkvenc 等硬件加速器

MPP 站在视频编解码链路上。RGA 不在这条链路上,它是旁边一条独立的支线。

但真正的产品里,两者几乎必然同时出现,因为它们的输入输出恰好互补:

objectivec 复制代码
              ┌──────────┐  NV12 / YUV420    ┌──────────┐  RGB / YUV      ┌──────────┐
  码流 ──▶    │ MPP DEC  │ ────────────────▶ │   RGA    │ ──────────────▶ │ 显示 DRM │
 H264/265     └──────────┘  解码帧(dmabuf)  └──────────┘  缩放/裁剪/      └──────────┘
                                                  │       旋转/格式转换
                                                  ├─────────────▶ MPP ENC(重新编码)
                                                  └─────────────▶ RKNN / OpenCV(AI 推理)

              ┌──────────┐    NV12 / RGB Bayer  ┌──────────┐   NV12 1920x1080  ┌──────────┐
  摄像头 ──▶  │   V4L2   │ ──────────────────▶ │   RGA    │ ────────────────▶ │ MPP ENC  │
              └──────────┘                      └──────────┘                   └──────────┘

码流经过 MPP 解码,出来的是 NV12 格式的解码帧,这是一个 dmabuf 句柄。这个帧接着送给 RGA,RGA 做缩放、裁剪、旋转、格式转换,然后把 RGB 或者 YUV 数据送给 DRM 显示,或者送给 MPP 重新编码,或者送给 RKNN 做 AI 推理。摄像头那条路也一样,V4L2 采集到的图像送给 RGA 预处理,再送给 MPP 编码。

一句话定位:MPP 管"帧的产生与压缩",RGA 管"帧的加工"。

遇到任何"对这一帧画面做几何或像素层面的变换"的需求,第一反应应该是问自己:这件事能不能交给 RGA,而不是 CPU 上的 libyuv 或者 swscale?


四、RGA 的软件栈由什么组成?

分两部分:用户态的 librga.so,和内核态的 RGA 驱动。

4.1 用户态:librga.so

官方原文:

RGA 模块支持库为 librga.so,通过对图像缓冲区结构体 struct rga_info 进行配置,实现相应的 2D 图形操作。为了获得更友好的开发体验,在此基础上进一步封装常用的 2D 图像操作接口。

librga 的设计有五条取向:

第一,接口定义参考 OpenCV 和 MATLAB 中常用的 2D 图形接口。 减少二次开发的学习成本,所以它叫 IM2D API。

第二,加入 RGA query 查询功能。 消除 RGA 硬件版本差异带来的兼容问题,查询版本信息、输入输出最大分辨率、图像格式支持情况。

第三,执行图像操作之前,需要对输入输出图像缓冲区做预处理。 调用 wrapbuffer_T 接口,把图像信息填充到 rga_buffer_t 结构体。

第四,对于 2D 图像复合操作,增加 improcess 接口。 通过传入一系列预定义的 usage 来执行复合操作。

第五,支持把单次无法完成的图像复合操作绑定为一个 RGA 图像任务,统一提交到驱动内逐个执行。 这就是任务模式,也叫 Job 模式。

4.2 内核态:RGA 驱动

官方原文:

驱动版本号分为主版本号、次版本号、修订版本号、编译版本号,四个等级版本号对应不同程度的功能更新,通常发布的 SDK 中 HAL 库与驱动是匹配的,librga 内部会进行校验版本,开发者无需关心该版本。

常见的驱动有三种:

驱动名称 硬件支持
RGA Device Driver RGA1、RGA2
RGA2 Device Driver RGA1、RGA2
RGA multicore Device Driver RGA2、RGA3

RK3588 搭载的是 RGA multicore Device Driver,简称 multi_rga driver。它需要同时管理 RK3588 上的 RGA2 加两颗 RGA3,一共三颗核。


五、版本对应关系:第一道门槛

这是最容易被忽略、却导致最多诡异现象的一步。官方给出的版本对应关系:

librga 版本 对应驱动 硬件支持
无版本号(旧版) 对应 SDK 内驱动 RGA1、RGA2
1.0.0 ~ 1.3.2 RGA Device Driver(kernel-4.4 及以上)/ RGA2 Device Driver(无版本号或 v2.1.0) RGA1、RGA2
> 1.4.0 RGA multicore Device Driver(v1.2.0 及以上) RGA2、RGA3
> 1.9.0 RGA Device Driver / RGA2 Device Driver / RGA multicore Device Driver RGA1、RGA2、RGA3

官方对版本不匹配的警告:

强烈不建议新版本 librga 搭配驱动或者旧版本 librga 搭配新内核使用,部分场景会有较明显的错误。

典型症状就是 RGB 和 YUV 互转的时候出现严重色偏,整体偏粉或者偏绿。

怎么分辨新旧版 librga?

无法获取版本号的旧版本 librga: 2020 年 11 月前发布的 SDK 中搭载的均为旧版,目前已经停止支持与维护。部分芯片平台,比如 RK3399 Linux SDK 2021 年 6 月前发布的 SDK(V2.5 及以下),也是旧版本。

支持查询版本号的新版本 librga: 源码目录下增加 im2d_api 目录,集成旧版接口,并推出 IM2D API,也可以叫 IM2D 版 librga。

新版本 librga 同时兼容旧的 RockchipRga 接口和 C_XXX 接口,可以平滑替换。

怎么查版本号?

查什么 怎么查
librga 版本 `strings librga.so
librga 版本 进程首次调用 RGA 时会自动打印 rga_api version 1.0.0_[0]
librga 版本 Android 上 `getprop
librga 版本 代码里调 querystring(RGA_VERSION)
驱动版本 `dmesg
驱动版本 cat /sys/kernel/debug/rkrga/driver_version
驱动版本 cat /proc/rkrga/driver_version

版本不匹配的典型症状

情况 症状
驱动过低 librga 启动兼容模式,日志提示 librga fail to get driver version! Compatibility mode will be enabled.
librga 过低 imStrError() 返回 Invalid parameters: invalid GraphicBuffer, can not get fd and virtual address 类报错
跨版本混用 严重的色彩偏差,RGB 和 YUV 转换时整体偏粉或偏绿

实战:怎么在板子上查版本?

第一步,查驱动版本。 这个节点需要 root 权限:

bash 复制代码
sudo cat /sys/kernel/debug/rkrga/driver_version

正常会输出类似:

yaml 复制代码
RGA multicore Device Driver: v1.3.3

这说明当前用的是 multicore 驱动,版本 1.3.3。对照版本对应表,落在 v1.2.0 及以上 的区间里,说明支持 RGA2 + RGA3 硬件,需要搭配 librga > 1.4.0。

另外,官方还提到 /proc/rkrga/driver_version 这个节点,但它只有在 kernel 开了 ROCKCHIP_RGA_PROC_FS 编译选项时才存在。如果 cat 报 No such file,说明当前 kernel 没开这个选项,走 /sys/kernel/debug/ 那条路径就行。

第二步,找到 librga.so 的位置。 直接在家目录敲 strings librga.so 会报 No such file,因为 librga.so 不在当前目录,它在系统库目录下。正确的做法是先让系统告诉你它在哪:

bash 复制代码
ldconfig -p | grep rga

正常会输出类似:

bash 复制代码
liblibrga.so (libc6,aarch64) => /usr/lib/aarch64-linux-gnu/librga.so

拿到路径后,再查版本:

bash 复制代码
strings /usr/lib/aarch64-linux-gnu/librga.so | grep rga_api | grep version

正常会输出类似:

css 复制代码
rga_api version 1.9.0_[0]

第三步,对照版本表确认是否匹配。 假设你查到 librga 是 1.9.0,驱动是 v1.3.3,那么:

  • librga > 1.4.0 ✅
  • 驱动 v1.2.0 及以上 ✅
  • 两者匹配,可以用

但如果查出来 librga 是 1.3.2 或更低,那就不匹配了,需要升级 librga。如果查不到版本号,说明是 2020 年 11 月前的旧版,官方已经停止维护,强烈建议升级。

第四步,如果嫌敲命令麻烦,直接跑官方 demo。 如果板子上有 rgaImDemo,直接跑:

bash 复制代码
rgaImDemo --querystring=version

正常会输出类似:

yaml 复制代码
rga_api version : v1.9.0 [0]
RGA version : RGA_3

这条命令一行就把 librga 版本和 RGA 硬件版本都告诉你了。或者直接跑任何用到 RGA 的程序,librga 在进程首次调用时会自动打印版本号:

ini 复制代码
rockchiprga: rga_api version 1.9.0_[0]

第五步,顺便把硬件拓扑也查了。 既然已经拿到 root,这几个节点一起查了:

bash 复制代码
# 三颗核的详细参数
sudo cat /sys/kernel/debug/rkrga/hardware

# 三颗核当前的负载
sudo cat /sys/kernel/debug/rkrga/load

# 调试开关状态
sudo cat /sys/kernel/debug/rkrga/debug

hardware 节点的输出会对每一颗核打印一段,大概长这样:

yaml 复制代码
rga3_core0, core 1: version: 3.0.76831
input range: 68x2 ~ 8176x8176
output range: 68x2 ~ 8128x8128
scale limit: 1/8 ~ 8
byte_stride_align: 16
max_byte_stride: 32768
csc: RGB2YUV 0xf YUV2RGB 0xf
feature: 0x4
mmu: RK_IOMMU
-----------------------------------
rga3_core1, core 2: version: 3.0.76831
...(同上)
-----------------------------------
rga2, core 4: version: 3.2.63318
input range: 2x2 ~ 8192x8192
output range: 2x2 ~ 4096x4096
scale limit: 1/16 ~ 16
byte_stride_align: 4
max_byte_stride: 32768
csc: RGB2YUV 0x7 YUV2RGB 0x7
feature: 0x5f
mmu: RGA_MMU

这段输出是你板子硬件拓扑的"体检报告",下一篇讲核能力差异时,我们要对着这张表逐条看。

第六步,万一 librga 版本不匹配怎么办? 官方给了几条路:

第一条,更新整个 SDK,最推荐,能避免依赖问题。

第二条,单独更新 librga。从 GitHub 预编译仓库拿:

arduino 复制代码
https://github.com/airockchip/librga

第三条,单独更新驱动。官方 FAQ 提到,可以通过更新包把旧驱动升到 multicore 驱动,或者把 multicore 驱动升到新版本。但这种方式需要重新编译 kernel,风险较高,一般建议走前两条路。


六、本篇小结

第一,RGA 是一个独立的 2D 硬件加速器。 专门干图像加工,包括缩放、旋转、裁剪、格式转换、alpha 混合、色键、ROP、马赛克、OSD 等。

第二,它的价值是把 CPU 从逐像素搬运里解放出来。 不和 CPU、GPU、VPU 抢计算资源。

第三,它的位置不在 MPP 编解码链路上,而是旁边一条独立支线。 MPP 负责帧的产生与压缩,RGA 负责帧的加工。

第四,它的边界是仍会占用 DDR 带宽,而且总线优先级是最低档。 这是后面性能问题的根源。

第五,软件栈由 librga.so 和 RGA 驱动两部分组成,两者版本必须匹配。

相关推荐
qetfw1 小时前
Debian 综合服务实训:Apache2、Samba、LDAP、vsftpd 与 OpenVPN
linux·服务器·debian
用户0510122572961 小时前
RGA(三)——实宽高、虚宽高与对齐约束
linux·嵌入式
fastjson_1 小时前
帆软看板 - 问题收集
linux·前端·javascript
jianpeng的工程笔记1 小时前
EL8 / EL9 安装 Slurm 26.05.4:主备控制器、MariaDB 记账与作业验收
linux·数据库·mariadb·高性能计算·slurm
程序员-Benothing1 小时前
Linux系统时间管理:date、timedatectl、NTP、Chrony配置
linux·运维·服务器
燕卫博1 小时前
SSD201 BSP 开发教程
嵌入式·bsp·ssd201
the3clipse2 小时前
MacOS、Linux 与 Windows 视频编解码对比:AV1、HEVC、ProRes 与硬件加速优劣势
linux·windows·macos·hevc·av1·视频解码·硬件解码
s6516654962 小时前
bootsect.s,setup.s,head.s的主要功能和对系统状态的影响、作用
linux
夜雪一千2 小时前
Python URL解码详解:单层、双重URL解码实战与踩坑指南
linux·服务器·python