diff --git a/docs/common/ai/cubie/_g2d-usage-guide.mdx b/docs/common/ai/cubie/_g2d-usage-guide.mdx new file mode 100644 index 000000000..a7817aea2 --- /dev/null +++ b/docs/common/ai/cubie/_g2d-usage-guide.mdx @@ -0,0 +1,236 @@ +## 概述 + +G2D 是 Allwinner SoC 集成的 2D 图形硬件加速器,负责图像旋转、缩放、格式转换、颜色填充等操作。 + +典型应用场景: + +- 视频编解码前后的图像预处理(缩放、色彩空间转换) +- 相机实时预览的图像处理 +- 显示输出前的格式转换(RGB ↔ YUV) +- 批量图像处理流水线 + +**本项目环境:** + +| 项目 | 值 | +| ------------ | ---------------------------------- | +| SoC | Allwinner A733 | +| Linux | 5.15.147-100-a733 | +| G2D 驱动版本 | 1.0.0 | +| 驱动模块 | `g2d_sunxi` | +| 设备节点 | `/dev/g2d`、`/dev/dma_heap/system` | + +## 环境准备 + +### 验证驱动状态 + + + +```bash +# 检查驱动模块是否已加载 +lsmod | grep g2d +# 输出类似: g2d_sunxi 90112 0 + +# 查看驱动版本 +cat /sys/module/g2d_sunxi/version +# 输出: 1.0.0 +``` + + + +若未加载,手动加载: + + + +```bash +sudo modprobe g2d_sunxi +``` + + + +### 设备节点权限 + +当前系统已配置为无需 root 运行: + +```text +/dev/g2d (0666) +/dev/dma_heap/system (0666) +``` + +如需重新配置 udev 规则: + + + +```bash +sudo sh -c 'echo "KERNEL==\"system\", SUBSYSTEM==\"dma_heap\", MODE=\"0666\"" > /etc/udev/rules.d/99-dma-heap.rules' +sudo udevadm control --reload-rules +sudo udevadm trigger +``` + + + +### 头文件 + +G2D API 头文件位于: + +```text +/usr/include/bsp/linux/sunxi-g2d.h +``` + +## 快速启动 + +### 核心概念 + +使用 G2D 的标准流程: + +```text +1. 分配 DMA buffer(图像数据缓冲区) +2. 填充源图像数据 +3. 配置 g2d_blit_h 结构体 +4. 调用 ioctl(G2D_CMD_BITBLT_H, ...) +5. 从目标 DMA buffer 读取结果 +6. 释放资源 +``` + +**关键:G2D 操作的是 DMA buffer,不是普通内存。** + +DMA buffer 由 `/dev/dma_heap/system` 分配,物理地址连续,硬件可直接访问。 + +### 示例(旋转 90°) + + + +```c +#include +#include +#include +#include +#include +#include +#include +#include + +#define W 1920 +#define H 1080 + +// 分配 DMA buffer,返回 fd 和虚拟地址 +static int alloc_dmabuf(int *fd, void **vaddr, size_t size) +{ + struct dma_heap_allocation_data alloc_data = { + .len = size, .fd_flags = O_RDWR | O_CLOEXEC, .heap_flags = 0, + }; + int heap_fd = open("/dev/dma_heap/system", O_RDONLY); + if (heap_fd < 0) return -1; + if (ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc_data) < 0) { + close(heap_fd); return -1; + } + close(heap_fd); + *fd = alloc_data.fd; + *vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); + if (*vaddr == MAP_FAILED) { close(*fd); return -1; } + return 0; +} + +int main(void) +{ + int g2d_fd, src_fd, dst_fd; + void *src_v, *dst_v; + g2d_blt_h blit; + + // 1. 分配两个 DMA buffer(源和目标) + alloc_dmabuf(&src_fd, &src_v, W * H * 4); + alloc_dmabuf(&dst_fd, &dst_v, W * H * 4); + + // 2. 填充源图像数据(渐变示例) + fill_pattern(src_v, W, H); + + // 3. 打开 G2D 设备 + g2d_fd = open("/dev/g2d", O_RDWR); + + // 4. 配置操作参数 + memset(&blit, 0, sizeof(blit)); + blit.flag_h = G2D_ROT_90; // 旋转 90° + + blit.src_image_h.fd = src_fd; + blit.src_image_h.format = G2D_FORMAT_ARGB8888; + blit.src_image_h.width = W; + blit.src_image_h.height = H; + + blit.dst_image_h.fd = dst_fd; + blit.dst_image_h.format = G2D_FORMAT_ARGB8888; + blit.dst_image_h.width = H; // 旋转后宽高互换 + blit.dst_image_h.height = W; + + // 5. 执行硬件加速操作 + ioctl(g2d_fd, G2D_CMD_BITBLT_H, (unsigned long)(&blit)); + + // 6. 结果已在 dst_v 中,验证或提交给后续流程 + + // 7. 释放资源 + close(g2d_fd); + munmap(src_v, W * H * 4); close(src_fd); + munmap(dst_v, W * H * 4); close(dst_fd); + return 0; +} +``` + + + +编译 + + + +```bash +sudo apt install gcc g++ cmake +gcc -o g2d_rotation g2d_rotation.c +``` + + + +## 示例运行结果 + +| 示例 | 操作 | 结果 | +| ----------------- | --------------------------- | -------------------------- | +| `g2d_rotation` | ARGB8888 1920×1080 旋转 90° | **8.24 ms**,251.8 MP/sec | +| `g2d_format_conv` | ARGB8888 → YUV420 1920×1080 | **9.56 ms**,216.8 MP/sec | +| `g2d_scaler` | 4096×4096 → 1920×1080 缩放 | **68.60 ms**,244.6 MP/sec | +| `g2d_color_fill` | 1920×1080 纯色填充 | **8.53 ms**,243.2 MP/sec | + +注:`g2d_scaler` 源图分辨率上限为 4096×4096(8192×8192 会触发 `EPERM`)。 + +## API 参考 + +完整 API 定义和所有支持格式见头文件: + +```text +/usr/include/bsp/linux/sunxi-g2d.h +``` + +常用 ioctl 命令: + +| 命令 | 用途 | +| -------------------- | ------------------------------------ | +| `G2D_CMD_BITBLT_H` | 单图像位块传输(旋转/缩放/格式转换) | +| `G2D_CMD_FILLRECT_H` | 颜色填充矩形 | +| `G2D_CMD_STRETCHBLT` | 伸缩位块传输 | +| `G2D_CMD_BLD_H` | Porter-Duff 混合操作 | +| `G2D_CMD_MIXER_TASK` | 批量任务(一次提交多个操作) | + +支持格式(部分): + +| 格式 | 说明 | +| ------------------------------- | --------------- | +| `G2D_FORMAT_ARGB8888` | 32bpp Alpha-RGB | +| `G2D_FORMAT_RGB888` | 24bpp RGB | +| `G2D_FORMAT_RGB565` | 16bpp | +| `G2D_FORMAT_YUV420UVC_U1V1U0V0` | NV12 标准格式 | + +旋转标志:`G2D_ROT_0` / `G2D_ROT_90` / `G2D_ROT_180` / `G2D_ROT_270` / `G2D_ROT_H`(水平翻转)/ `G2D_ROT_V`(垂直翻转) + +## 注意事项 + +- **DMA buffer 必须物理连续**,普通 `malloc` 不能用于 G2D +- **IOMMU 负责地址翻译**,G2D 访问的是 IOMMU 映射后的物理地址,无需关心具体地址值 +- **DMA buffer 通过 fd 传递**,用户空间用 `mmap` 后的虚拟地址读写 +- **目标分辨率应与源配合**,旋转 90° 时宽高互换 +- **格式转换**(如 RGB → YUV)由 G2D 硬件完成,源和目标 format 字段分别设置即可 +- **调试时**,失败返回 `-1`,`errno` 记录具体原因,用 `perror()` 打印 diff --git a/docs/common/ai/rockchip/_rga_usage_guide.mdx b/docs/common/ai/rockchip/_rga_usage_guide.mdx new file mode 100644 index 000000000..fc2081e00 --- /dev/null +++ b/docs/common/ai/rockchip/_rga_usage_guide.mdx @@ -0,0 +1,416 @@ +## RGA 简介 + +RGA (Raster Graphic Acceleration) 是 Rockchip 提供的 2D 图像处理硬件加速器,专门用于加速图像的缩放、颜色转换、格式转换等操作。在 RK3588 等芯片上可用。 + +**典型优势:** + +- 硬件加速,CPU 零开销 +- 高效的图像缩放 (resize) +- 色彩空间转换 (BGR↔RGB, RGB↔YUV) +- 支持 DMA 零拷贝 + +**适用场景:** + +- YOLO 等目标检测的图像预处理 +- 视频/图像的格式转换 +- 相机 pipeline 的图像处理 + +## RGA 快速上手 + +### 克隆仓库 + + + +```bash +git clone https://github.com/airockchip/librga.git +``` + + + +### 目录结构 + + + +```bash +./ +├── CHANGELOG.md +├── COPYING +├── docs +│ ├── RGA_FAQ.assets +│ ├── Rockchip_Developer_Guide_RGA_CN.md +│ ├── Rockchip_Developer_Guide_RGA_EN.md +│ ├── Rockchip_FAQ_RGA_CN.md +│ └── Rockchip_FAQ_RGA_EN.md +├── include +│ ├── drmrga.h +│ ├── GrallocOps.h +│ ├── im2d_buffer.h +│ ├── im2d_common.h +│ ├── im2d_expand.h +│ ├── im2d.h +│ ├── im2d.hpp +│ ├── im2d_mpi.h +│ ├── im2d_single.h +│ ├── im2d_task.h +│ ├── im2d_type.h +│ ├── im2d_version.h +│ ├── RgaApi.h +│ ├── rga.h +│ ├── RgaMutex.h +│ ├── RgaSingleton.h +│ ├── RgaUtils.h +│ └── RockchipRga.h +├── libs +│ ├── AndroidNdk +│ └── Linux +├── README.md +├── samples +│ ├── allocator_demo +│ ├── alpha_demo +│ ├── async_demo +│ ├── build +│ ├── cmake-android.sh +│ ├── cmake-linux.sh +│ ├── CMakeLists.txt +│ ├── config_demo +│ ├── copy_demo +│ ├── crop_demo +│ ├── cvtcolor_demo +│ ├── fill_demo +│ ├── gauss_demo +│ ├── im2d_api_demo +│ ├── mosaic_demo +│ ├── padding_demo +│ ├── palette_demo +│ ├── README.md +│ ├── resize_demo +│ ├── rop_demo +│ ├── sample_file +│ ├── SConscript +│ ├── toolchain_local.cmake +│ ├── transform_demo +│ └── utils +├── toolchains +│ ├── toolchain_android_ndk.cmake +│ ├── toolchain_linux_1106.cmake +│ ├── toolchain_linux.cmake +│ └── toolchain_rt_thread.cmake +└── tools + └── bin +``` + + + +### 运行 Demo + + + +```bash +cd librga/tools/bin/Linux/gcc-aarch64 +./rgaImDemo -h +``` + + + + + +```bash +./rgaImDemo --copy +``` + + + + + +```bash +./rgaImDemo --resize up +``` + + + +### 头文件与库文件 + +**头文件引用:** + +- RGA 头文件位置: `librga/include/` +- C++ 调用 im2d API:`im2d.hpp` +- C 调用 im2d API:`im2d.h` + +**库文件:** + +- RGA 库文件位置: `librga/libs/Linux/gcc-aarch64/` +- `librga.so` +- `librga.a` + +## 核心概念 + +### Buffer 管理 + +RGA 操作的是 buffer,需要先导入再用。 + + + +```cpp +#include +#include + +// 1. 分配用户态内存 +uint8_t* src_buf = malloc(width * height * 3); + +// 2. 导入到 RGA (虚拟地址方式) +rga_buffer_handle_t src_handle = importbuffer_virtualaddr(src_buf, buf_size); + +// 3. 包装成 rga_buffer_t +rga_buffer_t src_img = wrapbuffer_handle(src_handle, width, height, RK_FORMAT_BGR_888); + +// 4. 释放 +releasebuffer_handle(src_handle); +free(src_buf); +``` + + + +### 常用格式 + +| 格式 | 说明 | +| ------------------------ | ----------- | +| `RK_FORMAT_BGR_888` | 3 通道 BGR | +| `RK_FORMAT_RGB_888` | 3 通道 RGB | +| `RK_FORMAT_RGBA_8888` | 4 通道 RGBA | +| `RK_FORMAT_YCbCr_420_SP` | NV12 | + +### API 概览 + +| 操作 | API | 说明 | +| -------- | -------------- | -------------------- | +| 缩放 | `imresize()` | 图像缩放 | +| 颜色转换 | `imcvtcolor()` | BGR↔RGB, RGB↔YUV | +| 填充边框 | `imfill()` | 矩形区域填充 | +| 综合处理 | `improcess()` | crop+resize+格式转换 | +| 内存拷贝 | `imcopy()` | buffer 拷贝 | + +## 代码示例 + +### 简单示例:图像缩放 + + + +```cpp +#include +#include + +void resize_example() { + int src_w = 1920, src_h = 1080; + int dst_w = 640, dst_h = 640; + + // 分配内存 + uint8_t* src = malloc(src_w * src_h * 3); + uint8_t* dst = malloc(dst_w * dst_h * 3); + + // 导入 buffer + rga_buffer_handle_t src_handle = importbuffer_virtualaddr(src, src_w * src_h * 3); + rga_buffer_handle_t dst_handle = importbuffer_virtualaddr(dst, dst_w * dst_h * 3); + + // 包装 + rga_buffer_t src_img = wrapbuffer_handle(src_handle, src_w, src_h, RK_FORMAT_BGR_888); + rga_buffer_t dst_img = wrapbuffer_handle(dst_handle, dst_w, dst_h, RK_FORMAT_BGR_888); + + // 缩放 + IM_STATUS ret = imresize(src_img, dst_img); + + // 释放 + releasebuffer_handle(src_handle); + releasebuffer_handle(dst_handle); + free(src); + free(dst); +} +``` + + + +### 颜色转换 + + + +```cpp +// BGR -> RGB +imcvtcolor(src_img, dst_img, RK_FORMAT_BGR_888, RK_FORMAT_RGB_888); + +// BGR -> YUV (NV12) +imcvtcolor(src_img, dst_img, RK_FORMAT_BGR_888, RK_FORMAT_YCbCr_420_SP); +``` + + + +### 填充背景 + + + +```cpp +// 填充灰色矩形区域 +rga_buffer_t canvas = wrapbuffer_handle(handle, width, height, RK_FORMAT_BGR_888); + +// 灰色: B=114, G=114, R=114 (按 BGR 顺序) +int gray = (114 << 16) | (114 << 8) | 114; + +// 填充整个图像为灰色 +imfill(canvas, {0, 0, width, height}, gray); +``` + + + +### 综合处理 improcess() + +`improcess()` 是最强大的 API,可以同时完成: + +- 指定源区域 (crop) +- 缩放到目标区域 +- 颜色格式转换 + + + +```cpp +// 语法 +improcess(src_img, dst_img, {}, srect, drect, {}, -1, nullptr, nullptr, IM_SYNC); + +// 参数说明: +// src_img, dst_img: 源和目标 buffer +// {}: 第三个参数是 pat (pattern),一般不用 +// srect: 源区域 {x, y, width, height} +// drect: 目标区域 {x, y, width, height} +// {}: prect,一般不用 +// -1: acquire_fence_fd +// nullptr: release_fence_fd +// nullptr: opt_ptr +// IM_SYNC: 同步执行 +``` + + + +## YOLO 预处理中的使用 + +### 问题分析 + +YOLO 预处理需要: + +1. 保持纵横比的缩放 (letterbox) +2. 灰色填充边缘 +3. BGR → RGB 转换 + +### 完整实现 + + + +```cpp +int preprocess_with_rga(const cv::Mat& img0, int orig_w, int orig_h, + int target_size, float ratio, int dw, int dh, + std::vector& input_data, PerfStats& perf) { + Timer timer; + double t_padding = 0, t_resize = 0; + + int new_unpad_w = static_cast(orig_w * ratio); + int new_unpad_h = static_cast(orig_h * ratio); + + // RGA 要求 stride 和 width 像素数都按 16 对齐 + // BGR_888: stride_bytes 必须是 16 的倍数,且 width_px 也必须是 16 的倍数 + int src_width_px = ((orig_w + 15) / 16) * 16; + int dst_width_px = ((target_size + 15) / 16) * 16; + int src_stride = src_width_px * 3; + int dst_stride = dst_width_px * 3; + + int src_buf_size = src_stride * orig_h; + int dst_buf_size = dst_stride * target_size; + + std::vector src_buf(src_buf_size); + std::vector dst_buf(dst_buf_size); + + // 复制原图数据 (逐行拷贝,保留行间距) + for (int h = 0; h < orig_h; ++h) { + memcpy(src_buf.data() + h * src_stride, img0.data + h * orig_w * 3, orig_w * 3); + } + + // Step 1: RGA 填充灰色背景 + { + rga_buffer_handle_t canvas_handle = importbuffer_virtualaddr(dst_buf.data(), dst_width_px, target_size, RK_FORMAT_BGR_888); + if (canvas_handle == 0) { + std::cerr << "Warning: RGA importbuffer failed for canvas\n"; + return -1; + } + + rga_buffer_t canvas = wrapbuffer_handle(canvas_handle, dst_width_px, target_size, RK_FORMAT_BGR_888); + + int gray_color = (114 << 16) | (114 << 8) | 114; + + timer.reset(); + IM_STATUS ret = imfill(canvas, {0, 0, dst_width_px, target_size}, gray_color); + t_padding = timer.elapsed_ms(); + + if (ret != IM_STATUS_SUCCESS) { + std::cerr << "Warning: RGA imfill failed: " << imStrError(ret) << "\n"; + releasebuffer_handle(canvas_handle); + return -1; + } + + releasebuffer_handle(canvas_handle); + } + + // Step 2: RGA improcess - 缩放原图到中间区域 + BGR to RGB + { + rga_buffer_handle_t src_handle = importbuffer_virtualaddr(src_buf.data(), src_width_px, orig_h, RK_FORMAT_BGR_888); + rga_buffer_handle_t dst_handle = importbuffer_virtualaddr(dst_buf.data(), dst_width_px, target_size, RK_FORMAT_RGB_888); + + if (src_handle == 0 || dst_handle == 0) { + std::cerr << "Warning: RGA importbuffer failed\n"; + return -1; + } + + rga_buffer_t src_img = wrapbuffer_handle(src_handle, src_width_px, orig_h, RK_FORMAT_BGR_888); + rga_buffer_t dst_img = wrapbuffer_handle(dst_handle, dst_width_px, target_size, RK_FORMAT_RGB_888); + + im_rect srect = {0, 0, orig_w, orig_h}; + im_rect drect = {dw, dh, new_unpad_w, new_unpad_h}; + + timer.reset(); + IM_STATUS ret = improcess(src_img, dst_img, {}, srect, drect, {}, -1, nullptr, nullptr, IM_SYNC); + t_resize = timer.elapsed_ms(); + + if (ret != IM_STATUS_SUCCESS) { + std::cerr << "Warning: RGA improcess failed: " << imStrError(ret) << "\n"; + releasebuffer_handle(src_handle); + releasebuffer_handle(dst_handle); + return -1; + } + + releasebuffer_handle(src_handle); + releasebuffer_handle(dst_handle); + } + + // 复制到输出 + input_data = std::move(dst_buf); + + perf.preprocess = t_padding + t_resize; + return 0; +} +``` + + + +## 性能对比 + +```bash +================================================ + BENCHMARK RESULTS +================================================ + +Metric OpenCV RGA Speedup +-------------------------------------------------- +Preprocess (ms) 2.01 2.42 .83x +Inference (ms) 63.62 63.81 +TOTAL (ms) 128.30 126.93 +-------------------------------------------------- + +Iterations: 10 per version +Test completed. +``` + +可以看到在预处理非常简单的前提下,直接用 OpenCV 处理和 RGA 处理差异不大。 diff --git a/docs/cubie/a5e/app-dev/npu-dev/g2d-usage-guide.md b/docs/cubie/a5e/app-dev/npu-dev/g2d-usage-guide.md new file mode 100644 index 000000000..3b00a98bf --- /dev/null +++ b/docs/cubie/a5e/app-dev/npu-dev/g2d-usage-guide.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 4.5 + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/cubie/_g2d-usage-guide.mdx +--- + +# G2D 使用指南 + +import G2D from '../../../../common/ai/cubie/\_g2d-usage-guide.mdx'; + + diff --git a/docs/cubie/a7a/app-dev/npu-dev/g2d-usage-guide.md b/docs/cubie/a7a/app-dev/npu-dev/g2d-usage-guide.md new file mode 100644 index 000000000..3b00a98bf --- /dev/null +++ b/docs/cubie/a7a/app-dev/npu-dev/g2d-usage-guide.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 4.5 + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/cubie/_g2d-usage-guide.mdx +--- + +# G2D 使用指南 + +import G2D from '../../../../common/ai/cubie/\_g2d-usage-guide.mdx'; + + diff --git a/docs/cubie/a7s/app-dev/npu-dev/g2d-usage-guide.md b/docs/cubie/a7s/app-dev/npu-dev/g2d-usage-guide.md new file mode 100644 index 000000000..3b00a98bf --- /dev/null +++ b/docs/cubie/a7s/app-dev/npu-dev/g2d-usage-guide.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 4.5 + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/cubie/_g2d-usage-guide.mdx +--- + +# G2D 使用指南 + +import G2D from '../../../../common/ai/cubie/\_g2d-usage-guide.mdx'; + + diff --git a/docs/cubie/a7z/app-dev/npu-dev/g2d-usage-guide.md b/docs/cubie/a7z/app-dev/npu-dev/g2d-usage-guide.md new file mode 100644 index 000000000..3b00a98bf --- /dev/null +++ b/docs/cubie/a7z/app-dev/npu-dev/g2d-usage-guide.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 4.5 + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/cubie/_g2d-usage-guide.mdx +--- + +# G2D 使用指南 + +import G2D from '../../../../common/ai/cubie/\_g2d-usage-guide.mdx'; + + diff --git a/docs/rock5/rock5b/app-development/rga-usage-guide.md b/docs/rock5/rock5b/app-development/rga-usage-guide.md new file mode 100644 index 000000000..c98ccb70e --- /dev/null +++ b/docs/rock5/rock5b/app-development/rga-usage-guide.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 5 +description: "RGA 2D 图像加速开发指南" + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/rockchip/_rga_usage_guide.mdx +--- + +import RGA from '../../../common/ai/rockchip/\_rga_usage_guide.mdx'; + +# RGA 使用指南 + + diff --git a/i18n/en/docusaurus-plugin-content-docs/current/common/ai/cubie/_g2d-usage-guide.mdx b/i18n/en/docusaurus-plugin-content-docs/current/common/ai/cubie/_g2d-usage-guide.mdx new file mode 100644 index 000000000..efedbe332 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/common/ai/cubie/_g2d-usage-guide.mdx @@ -0,0 +1,238 @@ +## Overview + +G2D is a 2D graphics hardware accelerator integrated into Allwinner SoCs, responsible for image rotation, scaling, format conversion, color filling and other operations. + +Typical application scenarios: + +- Image preprocessing (scaling, color space conversion) before and after video encoding/decoding +- Camera real-time preview image processing +- Format conversion (RGB ↔ YUV) before display output +- Batch image processing pipeline + +**Project Environment:** + +| Item | Value | +| ------------------ | ---------------------------------- | +| SoC | Allwinner A733 | +| Linux | 5.15.147-100-a733 | +| G2D Driver Version | 1.0.0 | +| Driver Module | `g2d_sunxi` | +| Device Node | `/dev/g2d`, `/dev/dma_heap/system` | + +## Environment Setup + +### Verify Driver Status + + + +```bash +# Check if driver module is loaded +lsmod | grep g2d +# Output example: g2d_sunxi 90112 0 + +# Check driver version +cat /sys/module/g2d_sunxi/version +# Output: 1.0.0 +``` + + + +If not loaded, manually load: + + + +```bash +sudo modprobe g2d_sunxi +``` + + + +### Device Node Permissions + +Current system is configured to run without root: + +```text +/dev/g2d (0666) +/dev/dma_heap/system (0666) +``` + +To reconfigure udev rules if needed: + + + +```bash +sudo sh -c 'echo "KERNEL==\"system\", SUBSYSTEM==\"dma_heap\", MODE=\"0666\"" > /etc/udev/rules.d/99-dma-heap.rules' +sudo udevadm control --reload-rules +sudo udevadm trigger +``` + + + +### Header Files + +G2D API header file location: + +```text +/usr/include/bsp/linux/sunxi-g2d.h +``` + +## Quick Start + +### Core Concepts + +Standard workflow for using G2D: + +```text +1. Allocate DMA buffer (image data buffer) +2. Fill source image data +3. Configure g2d_blit_h structure +4. Call ioctl(G2D_CMD_BITBLT_H, ...) +5. Read result from target DMA buffer +6. Release resources +``` + +**Key: G2D operates on DMA buffer, not regular memory.** + +DMA buffer is allocated by `/dev/dma_heap/system`, physically contiguous, hardware can access directly. + +### Example (Rotate 90°) + +Complete runnable code see `g2d_rotation_or_mirror.c`. + + + +```c +#include +#include +#include +#include +#include +#include +#include +#include + +#define W 1920 +#define H 1080 + +// Allocate DMA buffer, return fd and virtual address +static int alloc_dmabuf(int *fd, void **vaddr, size_t size) +{ + struct dma_heap_allocation_data alloc_data = { + .len = size, .fd_flags = O_RDWR | O_CLOEXEC, .heap_flags = 0, + }; + int heap_fd = open("/dev/dma_heap/system", O_RDONLY); + if (heap_fd < 0) return -1; + if (ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc_data) < 0) { + close(heap_fd); return -1; + } + close(heap_fd); + *fd = alloc_data.fd; + *vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); + if (*vaddr == MAP_FAILED) { close(*fd); return -1; } + return 0; +} + +int main(void) +{ + int g2d_fd, src_fd, dst_fd; + void *src_v, *dst_v; + g2d_blt_h blit; + + // 1. Allocate two DMA buffers (source and destination) + alloc_dmabuf(&src_fd, &src_v, W * H * 4); + alloc_dmabuf(&dst_fd, &dst_v, W * H * 4); + + // 2. Fill source image data (gradient example) + fill_pattern(src_v, W, H); + + // 3. Open G2D device + g2d_fd = open("/dev/g2d", O_RDWR); + + // 4. Configure operation parameters + memset(&blit, 0, sizeof(blit)); + blit.flag_h = G2D_ROT_90; // Rotate 90° + + blit.src_image_h.fd = src_fd; + blit.src_image_h.format = G2D_FORMAT_ARGB8888; + blit.src_image_h.width = W; + blit.src_image_h.height = H; + + blit.dst_image_h.fd = dst_fd; + blit.dst_image_h.format = G2D_FORMAT_ARGB8888; + blit.dst_image_h.width = H; // Width and height swap after rotation + blit.dst_image_h.height = W; + + // 5. Execute hardware accelerated operation + ioctl(g2d_fd, G2D_CMD_BITBLT_H, (unsigned long)(&blit)); + + // 6. Result is already in dst_v, verify or submit to subsequent process + + // 7. Release resources + close(g2d_fd); + munmap(src_v, W * H * 4); close(src_fd); + munmap(dst_v, W * H * 4); close(dst_fd); + return 0; +} +``` + + + +Compilation + + + +```bash +sudo apt install gcc g++ cmake +gcc -o g2d_rotation g2d_rotation.c +``` + + + +## Example Results + +| Example | Operation | Result | +| ----------------- | ----------------------------- | -------------------------- | +| `g2d_rotation` | ARGB8888 1920×1080 rotate 90° | **8.24 ms**, 251.8 MP/sec | +| `g2d_format_conv` | ARGB8888 → YUV420 1920×1080 | **9.56 ms**, 216.8 MP/sec | +| `g2d_scaler` | 4096×4096 → 1920×1080 scale | **68.60 ms**, 244.6 MP/sec | +| `g2d_color_fill` | 1920×1080 solid color fill | **8.53 ms**, 243.2 MP/sec | + +Note: `g2d_scaler` source resolution upper limit is 4096×4096 (8192×8192 triggers `EPERM`). + +## API Reference + +Complete API definition and all supported formats see header file: + +```text +/usr/include/bsp/linux/sunxi-g2d.h +``` + +Common ioctl commands: + +| Command | Purpose | +| -------------------- | ------------------------------------------------------------- | +| `G2D_CMD_BITBLT_H` | Single image bit block transfer (rotate/scale/format convert) | +| `G2D_CMD_FILLRECT_H` | Color fill rectangle | +| `G2D_CMD_STRETCHBLT` | Stretch bit block transfer | +| `G2D_CMD_BLD_H` | Porter-Duff blend operation | +| `G2D_CMD_MIXER_TASK` | Batch tasks (submit multiple operations at once) | + +Supported formats (partial): + +| Format | Description | +| ------------------------------- | -------------------- | +| `G2D_FORMAT_ARGB8888` | 32bpp Alpha-RGB | +| `G2D_FORMAT_RGB888` | 24bpp RGB | +| `G2D_FORMAT_RGB565` | 16bpp | +| `G2D_FORMAT_YUV420UVC_U1V1U0V0` | NV12 standard format | + +Rotation flags: `G2D_ROT_0` / `G2D_ROT_90` / `G2D_ROT_180` / `G2D_ROT_270` / `G2D_ROT_H` (horizontal flip) / `G2D_ROT_V` (vertical flip) + +## Notes + +- **DMA buffer must be physically contiguous**, regular `malloc` cannot be used for G2D +- **IOMMU is responsible for address translation**, G2D accesses IOMMU-mapped physical addresses, no need to care about specific address values +- **DMA buffer passed through fd**, user space uses `mmap`-ed virtual address for read/write +- **Target resolution should match source**, width and height swap when rotating 90° +- **Format conversion** (e.g. RGB → YUV) is done by G2D hardware, just set source and destination format fields separately +- **For debugging**, failure returns `-1`, `errno` records specific reason, use `perror()` to print diff --git a/i18n/en/docusaurus-plugin-content-docs/current/common/ai/rockchip/_rga_usage_guide.mdx b/i18n/en/docusaurus-plugin-content-docs/current/common/ai/rockchip/_rga_usage_guide.mdx new file mode 100644 index 000000000..a9f1460da --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/common/ai/rockchip/_rga_usage_guide.mdx @@ -0,0 +1,416 @@ +## RGA Overview + +RGA (Raster Graphic Acceleration) is a 2D image processing hardware accelerator provided by Rockchip, specifically designed for accelerating image scaling, color conversion, format conversion and other operations. Available on RK3588 and other chips. + +**Typical Advantages:** + +- Hardware acceleration, zero CPU overhead +- Efficient image scaling (resize) +- Color space conversion (BGR↔RGB, RGB↔YUV) +- Supports DMA zero-copy + +**Application Scenarios:** + +- Image preprocessing for object detection like YOLO +- Video/image format conversion +- Camera pipeline image processing + +## RGA Quick Start + +### Clone Repository + + + +```bash +git clone https://github.com/airockchip/librga.git +``` + + + +### Directory Structure + + + +```bash +./ +├── CHANGELOG.md +├── COPYING +├── docs +│ ├── RGA_FAQ.assets +│ ├── Rockchip_Developer_Guide_RGA_CN.md +│ ├── Rockchip_Developer_Guide_RGA_EN.md +│ ├── Rockchip_FAQ_RGA_CN.md +│ └── Rockchip_FAQ_RGA_EN.md +├── include +│ ├── drmrga.h +│ ├── GrallocOps.h +│ ├── im2d_buffer.h +│ ├── im2d_common.h +│ ├── im2d_expand.h +│ ├── im2d.h +│ ├── im2d.hpp +│ ├── im2d_mpi.h +│ ├── im2d_single.h +│ ├── im2d_task.h +│ ├── im2d_type.h +│ ├── im2d_version.h +│ ├── RgaApi.h +│ ├── rga.h +│ ├── RgaMutex.h +│ ├── RgaSingleton.h +│ ├── RgaUtils.h +│ └── RockchipRga.h +├── libs +│ ├── AndroidNdk +│ └── Linux +├── README.md +├── samples +│ ├── allocator_demo +│ ├── alpha_demo +│ ├── async_demo +│ ├── build +│ ├── cmake-android.sh +│ ├── cmake-linux.sh +│ ├── CMakeLists.txt +│ ├── config_demo +│ ├── copy_demo +│ ├── crop_demo +│ ├── cvtcolor_demo +│ ├── fill_demo +│ ├── gauss_demo +│ ├── im2d_api_demo +│ ├── mosaic_demo +│ ├── padding_demo +│ ├── palette_demo +│ ├── README.md +│ ├── resize_demo +│ ├── rop_demo +│ ├── sample_file +│ ├── SConscript +│ ├── toolchain_local.cmake +│ ├── transform_demo +│ └── utils +├── toolchains +│ ├── toolchain_android_ndk.cmake +│ ├── toolchain_linux_1106.cmake +│ ├── toolchain_linux.cmake +│ └── toolchain_rt_thread.cmake +└── tools + └── bin +``` + + + +### Run Demo + + + +```bash +cd librga/tools/bin/Linux/gcc-aarch64 +./rgaImDemo -h +``` + + + + + +```bash +./rgaImDemo --copy +``` + + + + + +```bash +./rgaImDemo --resize up +``` + + + +### Header Files and Libraries + +**Header File References:** + +- RGA header location: `librga/include/` +- C++ call im2d API: `im2d.hpp` +- C call im2d API: `im2d.h` + +**Library Files:** + +- RGA library location: `librga/libs/Linux/gcc-aarch64/` +- `librga.so` +- `librga.a` + +## Core Concepts + +### Buffer Management + +RGA operates on buffers, which need to be imported first. + + + +```cpp +#include +#include + +// 1. Allocate user-space memory +uint8_t* src_buf = malloc(width * height * 3); + +// 2. Import to RGA (virtual address method) +rga_buffer_handle_t src_handle = importbuffer_virtualaddr(src_buf, buf_size); + +// 3. Wrap as rga_buffer_t +rga_buffer_t src_img = wrapbuffer_handle(src_handle, width, height, RK_FORMAT_BGR_888); + +// 4. Release +releasebuffer_handle(src_handle); +free(src_buf); +``` + + + +### Common Formats + +| Format | Description | +| ------------------------ | -------------- | +| `RK_FORMAT_BGR_888` | 3-channel BGR | +| `RK_FORMAT_RGB_888` | 3-channel RGB | +| `RK_FORMAT_RGBA_8888` | 4-channel RGBA | +| `RK_FORMAT_YCbCr_420_SP` | NV12 | + +### API Overview + +| Operation | API | Description | +| ------------------- | -------------- | ----------------------------- | +| Scale | `imresize()` | Image scaling | +| Color conversion | `imcvtcolor()` | BGR↔RGB, RGB↔YUV | +| Fill border | `imfill()` | Rectangle area fill | +| Combined processing | `improcess()` | crop+resize+format conversion | +| Memory copy | `imcopy()` | Buffer copy | + +## Code Examples + +### Simple Example: Image Scaling + + + +```cpp +#include +#include + +void resize_example() { + int src_w = 1920, src_h = 1080; + int dst_w = 640, dst_h = 640; + + // Allocate memory + uint8_t* src = malloc(src_w * src_h * 3); + uint8_t* dst = malloc(dst_w * dst_h * 3); + + // Import buffer + rga_buffer_handle_t src_handle = importbuffer_virtualaddr(src, src_w * src_h * 3); + rga_buffer_handle_t dst_handle = importbuffer_virtualaddr(dst, dst_w * dst_h * 3); + + // Wrap + rga_buffer_t src_img = wrapbuffer_handle(src_handle, src_w, src_h, RK_FORMAT_BGR_888); + rga_buffer_t dst_img = wrapbuffer_handle(dst_handle, dst_w, dst_h, RK_FORMAT_BGR_888); + + // Scale + IM_STATUS ret = imresize(src_img, dst_img); + + // Release + releasebuffer_handle(src_handle); + releasebuffer_handle(dst_handle); + free(src); + free(dst); +} +``` + + + +### Color Conversion + + + +```cpp +// BGR -> RGB +imcvtcolor(src_img, dst_img, RK_FORMAT_BGR_888, RK_FORMAT_RGB_888); + +// BGR -> YUV (NV12) +imcvtcolor(src_img, dst_img, RK_FORMAT_BGR_888, RK_FORMAT_YCbCr_420_SP); +``` + + + +### Fill Background + + + +```cpp +// Fill gray rectangle area +rga_buffer_t canvas = wrapbuffer_handle(handle, width, height, RK_FORMAT_BGR_888); + +// Gray: B=114, G=114, R=114 (BGR order) +int gray = (114 << 16) | (114 << 8) | 114; + +// Fill entire image with gray +imfill(canvas, {0, 0, width, height}, gray); +``` + + + +### Combined Processing improcess() + +`improcess()` is the most powerful API, can simultaneously: + +- Specify source region (crop) +- Scale to target region +- Color format conversion + + + +```cpp +// Syntax +improcess(src_img, dst_img, {}, srect, drect, {}, -1, nullptr, nullptr, IM_SYNC); + +// Parameter description: +// src_img, dst_img: source and destination buffer +// {}: third parameter is pat (pattern), generally not used +// srect: source region {x, y, width, height} +// drect: destination region {x, y, width, height} +// {}: prect, generally not used +// -1: acquire_fence_fd +// nullptr: release_fence_fd +// nullptr: opt_ptr +// IM_SYNC: synchronous execution +``` + + + +## Usage in YOLO Preprocessing + +### Problem Analysis + +YOLO preprocessing requires: + +1. Aspect ratio preserved scaling (letterbox) +2. Gray padding edges +3. BGR → RGB conversion + +### Complete Implementation + + + +```cpp +int preprocess_with_rga(const cv::Mat& img0, int orig_w, int orig_h, + int target_size, float ratio, int dw, int dh, + std::vector& input_data, PerfStats& perf) { + Timer timer; + double t_padding = 0, t_resize = 0; + + int new_unpad_w = static_cast(orig_w * ratio); + int new_unpad_h = static_cast(orig_h * ratio); + + // RGA requires both stride and width pixels to be 16-aligned + // BGR_888: stride_bytes must be multiple of 16, and width_px must also be multiple of 16 + int src_width_px = ((orig_w + 15) / 16) * 16; + int dst_width_px = ((target_size + 15) / 16) * 16; + int src_stride = src_width_px * 3; + int dst_stride = dst_width_px * 3; + + int src_buf_size = src_stride * orig_h; + int dst_buf_size = dst_stride * target_size; + + std::vector src_buf(src_buf_size); + std::vector dst_buf(dst_buf_size); + + // Copy original image data (line by line, preserve row spacing) + for (int h = 0; h < orig_h; ++h) { + memcpy(src_buf.data() + h * src_stride, img0.data + h * orig_w * 3, orig_w * 3); + } + + // Step 1: RGA fill gray background + { + rga_buffer_handle_t canvas_handle = importbuffer_virtualaddr(dst_buf.data(), dst_width_px, target_size, RK_FORMAT_BGR_888); + if (canvas_handle == 0) { + std::cerr << "Warning: RGA importbuffer failed for canvas\n"; + return -1; + } + + rga_buffer_t canvas = wrapbuffer_handle(canvas_handle, dst_width_px, target_size, RK_FORMAT_BGR_888); + + int gray_color = (114 << 16) | (114 << 8) | 114; + + timer.reset(); + IM_STATUS ret = imfill(canvas, {0, 0, dst_width_px, target_size}, gray_color); + t_padding = timer.elapsed_ms(); + + if (ret != IM_STATUS_SUCCESS) { + std::cerr << "Warning: RGA imfill failed: " << imStrError(ret) << "\n"; + releasebuffer_handle(canvas_handle); + return -1; + } + + releasebuffer_handle(canvas_handle); + } + + // Step 2: RGA improcess - scale original to center region + BGR to RGB + { + rga_buffer_handle_t src_handle = importbuffer_virtualaddr(src_buf.data(), src_width_px, orig_h, RK_FORMAT_BGR_888); + rga_buffer_handle_t dst_handle = importbuffer_virtualaddr(dst_buf.data(), dst_width_px, target_size, RK_FORMAT_RGB_888); + + if (src_handle == 0 || dst_handle == 0) { + std::cerr << "Warning: RGA importbuffer failed\n"; + return -1; + } + + rga_buffer_t src_img = wrapbuffer_handle(src_handle, src_width_px, orig_h, RK_FORMAT_BGR_888); + rga_buffer_t dst_img = wrapbuffer_handle(dst_handle, dst_width_px, target_size, RK_FORMAT_RGB_888); + + im_rect srect = {0, 0, orig_w, orig_h}; + im_rect drect = {dw, dh, new_unpad_w, new_unpad_h}; + + timer.reset(); + IM_STATUS ret = improcess(src_img, dst_img, {}, srect, drect, {}, -1, nullptr, nullptr, IM_SYNC); + t_resize = timer.elapsed_ms(); + + if (ret != IM_STATUS_SUCCESS) { + std::cerr << "Warning: RGA improcess failed: " << imStrError(ret) << "\n"; + releasebuffer_handle(src_handle); + releasebuffer_handle(dst_handle); + return -1; + } + + releasebuffer_handle(src_handle); + releasebuffer_handle(dst_handle); + } + + // Copy to output + input_data = std::move(dst_buf); + + perf.preprocess = t_padding + t_resize; + return 0; +} +``` + + + +## Performance Comparison + +```bash +================================================ + BENCHMARK RESULTS +================================================ + +Metric OpenCV RGA Speedup +-------------------------------------------------- +Preprocess (ms) 2.01 2.42 .83x +Inference (ms) 63.62 63.81 +TOTAL (ms) 128.30 126.93 +-------------------------------------------------- + +Iterations: 10 per version +Test completed. +``` + +As you can see, with very simple preprocessing, OpenCV and RGA have minimal difference. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/cubie/a5e/app-dev/npu-dev/g2d-usage-guide.md b/i18n/en/docusaurus-plugin-content-docs/current/cubie/a5e/app-dev/npu-dev/g2d-usage-guide.md new file mode 100644 index 000000000..7a0e4ce9f --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/cubie/a5e/app-dev/npu-dev/g2d-usage-guide.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 4.5 + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/cubie/_g2d-usage-guide.mdx +--- + +# G2D Usage Guide + +import G2D from '../../../../common/ai/cubie/\_g2d-usage-guide.mdx'; + + diff --git a/i18n/en/docusaurus-plugin-content-docs/current/cubie/a7a/app-dev/npu-dev/g2d-usage-guide.md b/i18n/en/docusaurus-plugin-content-docs/current/cubie/a7a/app-dev/npu-dev/g2d-usage-guide.md new file mode 100644 index 000000000..7a0e4ce9f --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/cubie/a7a/app-dev/npu-dev/g2d-usage-guide.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 4.5 + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/cubie/_g2d-usage-guide.mdx +--- + +# G2D Usage Guide + +import G2D from '../../../../common/ai/cubie/\_g2d-usage-guide.mdx'; + + diff --git a/i18n/en/docusaurus-plugin-content-docs/current/cubie/a7s/app-dev/npu-dev/g2d-usage-guide.md b/i18n/en/docusaurus-plugin-content-docs/current/cubie/a7s/app-dev/npu-dev/g2d-usage-guide.md new file mode 100644 index 000000000..7a0e4ce9f --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/cubie/a7s/app-dev/npu-dev/g2d-usage-guide.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 4.5 + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/cubie/_g2d-usage-guide.mdx +--- + +# G2D Usage Guide + +import G2D from '../../../../common/ai/cubie/\_g2d-usage-guide.mdx'; + + diff --git a/i18n/en/docusaurus-plugin-content-docs/current/cubie/a7z/app-dev/npu-dev/g2d-usage-guide.md b/i18n/en/docusaurus-plugin-content-docs/current/cubie/a7z/app-dev/npu-dev/g2d-usage-guide.md new file mode 100644 index 000000000..7a0e4ce9f --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/cubie/a7z/app-dev/npu-dev/g2d-usage-guide.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 4.5 + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/cubie/_g2d-usage-guide.mdx +--- + +# G2D Usage Guide + +import G2D from '../../../../common/ai/cubie/\_g2d-usage-guide.mdx'; + + diff --git a/i18n/en/docusaurus-plugin-content-docs/current/rock5/rock5b/app-development/rga-usage-guide.md b/i18n/en/docusaurus-plugin-content-docs/current/rock5/rock5b/app-development/rga-usage-guide.md new file mode 100644 index 000000000..5564e8b4a --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/rock5/rock5b/app-development/rga-usage-guide.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 5 +description: "RGA 2D Image Acceleration Development Guide" + +doc_kind: wrapper +source_of_truth: common +imports_resolve_to: + - docs/common/ai/rockchip/_rga_usage_guide.mdx +--- + +import RGA from '../../../common/ai/rockchip/\_rga_usage_guide.mdx'; + +# RGA Usage Guide + +