一、为什么单独讲这一篇?
前两篇讲了 RGA 是什么、RK3588 上有几颗核。从这一篇开始,要讲真正会"让你踩坑"的东西了。
在 RGA 的日常使用中,超过八成的"花屏""失败""图像不对"问题,都源于对"实宽高/虚宽高"和"对齐约束"的理解不到位 。官方 FAQ 里单独列了一节讲对齐,内核调试节点里有一个 check 模式专门检查对齐------说明这个问题官方自己也知道容易出错。
这一篇就把这两件事讲透。
二、实宽高(aw/ah)与虚宽高(vw/vh)
2.1 先看一个真实的报错
如果你在调用 RGA 时看到这样的报错:
css
err ws[100,1280,1280]
Error srcRect
这是什么意思?官方 FAQ 给出了明确解释:
该报错为明显的参数报错,"err ws"即虚宽(width stride)参数异常,其后"\[\]"内的参数分别为 x_offset, width, width_stride,这里由于 X 方向的偏移与实际操作区域的宽的和大于了虚宽,所以 librga 认为虚宽存在问题而返回的报错。
翻译一下:err ws[100,1280,1280] 表示 X 方向偏移是 100,实际操作区域宽度是 1280,虚宽是 1280。因为 100 + 1280 = 1380 > 1280,超出了虚宽范围,所以报错。
解决方案:把虚宽改为 1380,或者把实宽改为 1180。
2.2 四个概念,一次说清
| 缩写 | 官方名称 | 含义 | 对应字段 |
|---|---|---|---|
| aw / ah | active width / active height | 实宽实高,本次实际操作区域 | im_rect.width / im_rect.height |
| vw / vh | virtual width / virtual height | 虚宽虚高,图像 buffer 本身大小(即 stride) | rga_buffer_t.width / rga_buffer_t.height |
| xoff / yoff | x offset / y offset | 操作区域相对 buffer 原点的偏移 | im_rect.x / im_rect.y |
画个图就清楚了:
ini
vw(虚宽 = width stride)
├────────────────────────────────────────┤
│ │
│ xoff = 100 │
│ ┌──────────────┐ │
│ │ │ │ vh(虚高)
│ │ 实际操作区域 │ ah = 300 │
│ │ │ │
│ └──────────────┘ │
│ aw = 300 │
└────────────────────────────────────────┘
官方对 im_rect 的约束说得很清楚:
实际操作区域不能超出图像大小,即 (x + width) <= wstride ,(y + height) <= hstride。
违反这条约束,就是"err ws"报错的直接原因。
2.3 为什么会有虚宽这个概念?
因为 RGA 硬件是按 字(word,32bit) 方式取数的。
- RGBA8888:单像素 32bit = 1 word → 无对齐要求(RGA2 下)
- RGB565:单像素 16bit → 需 2 对齐(凑满一个 word)
- RGB888:单像素 24bit → 需 4 对齐(4 个像素 = 3 个 word)
- YUV:Y 通道单像素 8bit → Y 通道需 4 对齐 ;同时 4:2:0/4:2:2 下采样特性要求 x_offset、y_offset、width、height 都 2 对齐。
官方还给了对齐的计算公式:
width stride 对齐 = lcm(bpp, byte_stride × 8) / pixel_stride
| 符号 | 含义 | 举例 |
|---|---|---|
| bpp | bit per pixel,单像素占多少 bit | RGBA8888 = 32,RGB565 = 16,RGB888 = 24,YUV 的 Y 通道 = 8 |
| byte_stride | 硬件取数的字节颗粒度 | RGA2 = 4 ,RGA3 = 16 |
| byte_stride × 8 | 把字节颗粒度换算成 bit | RGA2 = 32 bit,RGA3 = 128 bit |
| pixel_stride | 单像素占多少 bit(注意:和 bpp 数值一样,但语义不同) | 和 bpp 同值 |
| lcm(x, y) | x 和 y 的最小公倍数 | lcm(32, 32) = 32,lcm(24, 32) = 96 |
| 公式结果 | width stride 需要对齐到多少个像素 | 结果 = 4 表示必须按 4 个像素的倍数对齐 |
简单说,虚宽不是随便写的,必须满足硬件按 word 取数的要求。
三、各平台各格式的对齐要求(核心表格)
官方对齐表分 RGA2 和 RGA3 两套,这里分别列出。
3.1 RGA2 的对齐要求
| 格式 | 对齐要求 |
|---|---|
| RGBA/BGRA/ARGB/ABGR/RGBX/BGRX/XRGB/XBGR 8888 | width stride 无对齐要求 |
| RGBA_4444 / ARGB_5551 / RGB_565 等 16bit | width stride 须 2 对齐 |
| YUYV / YVYU / UYVY / VYUY 420/422 | width stride 须 2 对齐,x_offset、y_offset、width、height、height stride 均须 2 对齐 |
| RGB_888 / BGR_888 / A8 | width stride 须 4 对齐 |
| YCbCr 420/422/444 SP/P、Y400、Y4、Y8 | width stride 须 4 对齐,x_offset、y_offset、width、height、height stride 均须 2 对齐 |
| YCbCr 420/422 SP 10B | width stride 须 16 对齐,x_offset、y_offset、width、height、height stride 均须 2 对齐 |
3.2 RGA3 的对齐要求
| 格式 | 对齐要求 |
|---|---|
| RGBA 系 8888 | width stride 须 4 对齐 |
| RGB_565 / BGR_565 | width stride 须 8 对齐 |
| YUYV / UYVY 等 422 | width stride 须 8 对齐,x_offset、y_offset、width、height、height stride 均须 2 对齐 |
| RGB_888 / BGR_888 | width stride 须 16 对齐 |
| YCbCr 420/422 SP | width stride 须 16 对齐,x_offset、y_offset、width、height、height stride 均须 2 对齐 |
| YCbCr 420/422 SP 10B | width stride 须 64 对齐,x_offset、y_offset、width、height、height stride 均须 2 对齐 |
| FBC mode | 除上述格式对齐要求外,width stride、height stride 须 16 对齐 |
| TILE 8×8 mode | 除上述格式对齐要求外,width、height 须 8 对齐 ,输入通道 width stride、height stride 须 16 对齐 |
四、RK3588 的特殊规则:取最严约束
RK3588 同时搭载 RGA2 和 RGA3,而两者的对齐要求不同。官方对此有明确说明:
当芯片平台搭载多版本硬件时,为了保证硬件利用率,librga 会按最严格的对齐要求进行约束。
具体来说:
- RGA2 的
byte_stride_align是 4 - RGA3 的
byte_stride_align是 16
所以 librga 在 RK3588 上会统一按 16 对齐校验。
这意味着:你在准备 NV12 的 stride 时,不能按 RGA2 时代的 4 来算,要按 16 来算。
举个具体的例子:你要处理一帧 1280×720 的 NV12 图像。
- 如果按 RGA2 的标准,stride 写 1280(刚好 4 对齐)
- 但 RK3588 会按 RGA3 的标准校验,要求 16 对齐
- 所以 stride 必须写
ALIGN(1280, 16)= 1280(刚好也是 16 的倍数,没问题) - 但如果分辨率是 1281 或 1282,stride 就必须往上取到 16 的倍数
同样,10bit NV12 的 stride 要按 64 对齐准备,而不是 RGA2 时代的 16。
五、实战中的对齐检查
5.1 用 imcheck 在调试阶段校验
librga 提供了 imcheck() 接口用于校验参数合法性:
imcheck() 接口作为调用 librga 的校验接口,它将判断即将传递到 librga 内部的数据结构的参数是否正确、功能是否支持、是否触发硬件限制等。
如果校验失败,返回的错误信息会明确指出原因。比如:
ini
Invalid parameters: dst, Error yuv not align to 2,
rect[x,y,w,h] = [0,0,1281,720], wstride = 1281, hstride = 720, format = 0xa00(nv12)
这说明 YUV 格式的宽度 1281 不是 2 对齐,所以校验失败。
5.2 常见对齐问题的诊断
| 报错/现象 | 原因 | 对策 |
|---|---|---|
err ws[100,1280,1280] |
x_offset + width > width_stride | 改虚宽为 1380,或改实宽为 1180 |
Error yuv not align to 2 |
YUV 宽度不是 2 对齐 | 宽度改为偶数 |
| RGB888 缩放后有黑线/斜的 | RGB888 的 width stride 未 4(或 16)对齐 | 检查 stride 对齐 |
| 图像出现黑色或绿色小条纹 | buffer 使能了 cache 但未同步 | 同步 cache,或分配非 cache buffer |
六、本篇小结
第一,实宽高(aw/ah)是本次实际操作区域,虚宽高(vw/vh)是图像 buffer 本身大小。 约束是 x + width <= wstride,y + height <= hstride,违反就会报 "err ws"。
第二,对齐要求来自硬件按 word(32bit)取数的特性。 RGBA8888 无对齐(RGA2)/ 4 对齐(RGA3),RGB565 2 / 8,RGB888 4 / 16,YUV 4 / 16,10bit YUV 16 / 64。
第三,YUV 族的 x_offset、y_offset、width、height、height stride 均须 2 对齐。 10bit YUV 的 64 对齐是加在 width stride 上的,不要和 2 对齐混。
第四,RK3588 上按最严约束执行,也就是 RGA3 的 16 对齐标准。 NV12 的 stride 要按 16 准备,10bit NV12 要按 64 准备。
第五,调试阶段用 imcheck() 校验参数。 它会在调用驱动之前就把参数问题找出来,报错信息会直接告诉你是哪个格式、哪个参数不符合要求。