|
| 1 | +## 概述 |
| 2 | + |
| 3 | +G2D 是 Allwinner SoC 集成的 2D 图形硬件加速器,负责图像旋转、缩放、格式转换、颜色填充等操作。 |
| 4 | + |
| 5 | +典型应用场景: |
| 6 | + |
| 7 | +- 视频编解码前后的图像预处理(缩放、色彩空间转换) |
| 8 | +- 相机实时预览的图像处理 |
| 9 | +- 显示输出前的格式转换(RGB ↔ YUV) |
| 10 | +- 批量图像处理流水线 |
| 11 | + |
| 12 | +**本项目环境:** |
| 13 | + |
| 14 | +| 项目 | 值 | |
| 15 | +| ------------ | ---------------------------------- | |
| 16 | +| SoC | Allwinner A733 | |
| 17 | +| Linux | 5.15.147-100-a733 | |
| 18 | +| G2D 驱动版本 | 1.0.0 | |
| 19 | +| 驱动模块 | `g2d_sunxi` | |
| 20 | +| 设备节点 | `/dev/g2d`、`/dev/dma_heap/system` | |
| 21 | + |
| 22 | +## 环境准备 |
| 23 | + |
| 24 | +### 验证驱动状态 |
| 25 | + |
| 26 | +<NewCodeBlock tip="Device" type="device"> |
| 27 | + |
| 28 | +```bash |
| 29 | +# 检查驱动模块是否已加载 |
| 30 | +lsmod | grep g2d |
| 31 | +# 输出类似: g2d_sunxi 90112 0 |
| 32 | + |
| 33 | +# 查看驱动版本 |
| 34 | +cat /sys/module/g2d_sunxi/version |
| 35 | +# 输出: 1.0.0 |
| 36 | +``` |
| 37 | + |
| 38 | +</NewCodeBlock> |
| 39 | + |
| 40 | +若未加载,手动加载: |
| 41 | + |
| 42 | +<NewCodeBlock tip="Device" type="device"> |
| 43 | + |
| 44 | +```bash |
| 45 | +sudo modprobe g2d_sunxi |
| 46 | +``` |
| 47 | + |
| 48 | +</NewCodeBlock> |
| 49 | + |
| 50 | +### 设备节点权限 |
| 51 | + |
| 52 | +当前系统已配置为无需 root 运行: |
| 53 | + |
| 54 | +```text |
| 55 | +/dev/g2d (0666) |
| 56 | +/dev/dma_heap/system (0666) |
| 57 | +``` |
| 58 | + |
| 59 | +如需重新配置 udev 规则: |
| 60 | + |
| 61 | +<NewCodeBlock tip="Device" type="device"> |
| 62 | + |
| 63 | +```bash |
| 64 | +sudo sh -c 'echo "KERNEL==\"system\", SUBSYSTEM==\"dma_heap\", MODE=\"0666\"" > /etc/udev/rules.d/99-dma-heap.rules' |
| 65 | +sudo udevadm control --reload-rules |
| 66 | +sudo udevadm trigger |
| 67 | +``` |
| 68 | + |
| 69 | +</NewCodeBlock> |
| 70 | + |
| 71 | +### 头文件 |
| 72 | + |
| 73 | +G2D API 头文件位于: |
| 74 | + |
| 75 | +```text |
| 76 | +/usr/include/bsp/linux/sunxi-g2d.h |
| 77 | +``` |
| 78 | + |
| 79 | +## 快速启动 |
| 80 | + |
| 81 | +### 核心概念 |
| 82 | + |
| 83 | +使用 G2D 的标准流程: |
| 84 | + |
| 85 | +```text |
| 86 | +1. 分配 DMA buffer(图像数据缓冲区) |
| 87 | +2. 填充源图像数据 |
| 88 | +3. 配置 g2d_blit_h 结构体 |
| 89 | +4. 调用 ioctl(G2D_CMD_BITBLT_H, ...) |
| 90 | +5. 从目标 DMA buffer 读取结果 |
| 91 | +6. 释放资源 |
| 92 | +``` |
| 93 | + |
| 94 | +**关键:G2D 操作的是 DMA buffer,不是普通内存。** |
| 95 | + |
| 96 | +DMA buffer 由 `/dev/dma_heap/system` 分配,物理地址连续,硬件可直接访问。 |
| 97 | + |
| 98 | +### 示例(旋转 90°) |
| 99 | + |
| 100 | +<NewCodeBlock tip="Device" type="device"> |
| 101 | + |
| 102 | +```c |
| 103 | +#include <stdio.h> |
| 104 | +#include <stdlib.h> |
| 105 | +#include <fcntl.h> |
| 106 | +#include <unistd.h> |
| 107 | +#include <sys/ioctl.h> |
| 108 | +#include <bsp/linux/sunxi-g2d.h> |
| 109 | +#include <linux/dma-heap.h> |
| 110 | +#include <sys/mman.h> |
| 111 | + |
| 112 | +#define W 1920 |
| 113 | +#define H 1080 |
| 114 | + |
| 115 | +// 分配 DMA buffer,返回 fd 和虚拟地址 |
| 116 | +static int alloc_dmabuf(int *fd, void **vaddr, size_t size) |
| 117 | +{ |
| 118 | + struct dma_heap_allocation_data alloc_data = { |
| 119 | + .len = size, .fd_flags = O_RDWR | O_CLOEXEC, .heap_flags = 0, |
| 120 | + }; |
| 121 | + int heap_fd = open("/dev/dma_heap/system", O_RDONLY); |
| 122 | + if (heap_fd < 0) return -1; |
| 123 | + if (ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc_data) < 0) { |
| 124 | + close(heap_fd); return -1; |
| 125 | + } |
| 126 | + close(heap_fd); |
| 127 | + *fd = alloc_data.fd; |
| 128 | + *vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); |
| 129 | + if (*vaddr == MAP_FAILED) { close(*fd); return -1; } |
| 130 | + return 0; |
| 131 | +} |
| 132 | + |
| 133 | +int main(void) |
| 134 | +{ |
| 135 | + int g2d_fd, src_fd, dst_fd; |
| 136 | + void *src_v, *dst_v; |
| 137 | + g2d_blt_h blit; |
| 138 | + |
| 139 | + // 1. 分配两个 DMA buffer(源和目标) |
| 140 | + alloc_dmabuf(&src_fd, &src_v, W * H * 4); |
| 141 | + alloc_dmabuf(&dst_fd, &dst_v, W * H * 4); |
| 142 | + |
| 143 | + // 2. 填充源图像数据(渐变示例) |
| 144 | + fill_pattern(src_v, W, H); |
| 145 | + |
| 146 | + // 3. 打开 G2D 设备 |
| 147 | + g2d_fd = open("/dev/g2d", O_RDWR); |
| 148 | + |
| 149 | + // 4. 配置操作参数 |
| 150 | + memset(&blit, 0, sizeof(blit)); |
| 151 | + blit.flag_h = G2D_ROT_90; // 旋转 90° |
| 152 | + |
| 153 | + blit.src_image_h.fd = src_fd; |
| 154 | + blit.src_image_h.format = G2D_FORMAT_ARGB8888; |
| 155 | + blit.src_image_h.width = W; |
| 156 | + blit.src_image_h.height = H; |
| 157 | + |
| 158 | + blit.dst_image_h.fd = dst_fd; |
| 159 | + blit.dst_image_h.format = G2D_FORMAT_ARGB8888; |
| 160 | + blit.dst_image_h.width = H; // 旋转后宽高互换 |
| 161 | + blit.dst_image_h.height = W; |
| 162 | + |
| 163 | + // 5. 执行硬件加速操作 |
| 164 | + ioctl(g2d_fd, G2D_CMD_BITBLT_H, (unsigned long)(&blit)); |
| 165 | + |
| 166 | + // 6. 结果已在 dst_v 中,验证或提交给后续流程 |
| 167 | + |
| 168 | + // 7. 释放资源 |
| 169 | + close(g2d_fd); |
| 170 | + munmap(src_v, W * H * 4); close(src_fd); |
| 171 | + munmap(dst_v, W * H * 4); close(dst_fd); |
| 172 | + return 0; |
| 173 | +} |
| 174 | +``` |
| 175 | +
|
| 176 | +</NewCodeBlock> |
| 177 | +
|
| 178 | +编译 |
| 179 | +
|
| 180 | +<NewCodeBlock tip="Device" type="device"> |
| 181 | +
|
| 182 | +```bash |
| 183 | +sudo apt install gcc g++ cmake |
| 184 | +gcc -o g2d_rotation g2d_rotation.c |
| 185 | +``` |
| 186 | + |
| 187 | +</NewCodeBlock> |
| 188 | + |
| 189 | +## 示例运行结果 |
| 190 | + |
| 191 | +| 示例 | 操作 | 结果 | |
| 192 | +| ----------------- | --------------------------- | -------------------------- | |
| 193 | +| `g2d_rotation` | ARGB8888 1920×1080 旋转 90° | **8.24 ms**,251.8 MP/sec | |
| 194 | +| `g2d_format_conv` | ARGB8888 → YUV420 1920×1080 | **9.56 ms**,216.8 MP/sec | |
| 195 | +| `g2d_scaler` | 4096×4096 → 1920×1080 缩放 | **68.60 ms**,244.6 MP/sec | |
| 196 | +| `g2d_color_fill` | 1920×1080 纯色填充 | **8.53 ms**,243.2 MP/sec | |
| 197 | + |
| 198 | +注:`g2d_scaler` 源图分辨率上限为 4096×4096(8192×8192 会触发 `EPERM`)。 |
| 199 | + |
| 200 | +## API 参考 |
| 201 | + |
| 202 | +完整 API 定义和所有支持格式见头文件: |
| 203 | + |
| 204 | +```text |
| 205 | +/usr/include/bsp/linux/sunxi-g2d.h |
| 206 | +``` |
| 207 | + |
| 208 | +常用 ioctl 命令: |
| 209 | + |
| 210 | +| 命令 | 用途 | |
| 211 | +| -------------------- | ------------------------------------ | |
| 212 | +| `G2D_CMD_BITBLT_H` | 单图像位块传输(旋转/缩放/格式转换) | |
| 213 | +| `G2D_CMD_FILLRECT_H` | 颜色填充矩形 | |
| 214 | +| `G2D_CMD_STRETCHBLT` | 伸缩位块传输 | |
| 215 | +| `G2D_CMD_BLD_H` | Porter-Duff 混合操作 | |
| 216 | +| `G2D_CMD_MIXER_TASK` | 批量任务(一次提交多个操作) | |
| 217 | + |
| 218 | +支持格式(部分): |
| 219 | + |
| 220 | +| 格式 | 说明 | |
| 221 | +| ------------------------------- | --------------- | |
| 222 | +| `G2D_FORMAT_ARGB8888` | 32bpp Alpha-RGB | |
| 223 | +| `G2D_FORMAT_RGB888` | 24bpp RGB | |
| 224 | +| `G2D_FORMAT_RGB565` | 16bpp | |
| 225 | +| `G2D_FORMAT_YUV420UVC_U1V1U0V0` | NV12 标准格式 | |
| 226 | + |
| 227 | +旋转标志:`G2D_ROT_0` / `G2D_ROT_90` / `G2D_ROT_180` / `G2D_ROT_270` / `G2D_ROT_H`(水平翻转)/ `G2D_ROT_V`(垂直翻转) |
| 228 | + |
| 229 | +## 注意事项 |
| 230 | + |
| 231 | +- **DMA buffer 必须物理连续**,普通 `malloc` 不能用于 G2D |
| 232 | +- **IOMMU 负责地址翻译**,G2D 访问的是 IOMMU 映射后的物理地址,无需关心具体地址值 |
| 233 | +- **DMA buffer 通过 fd 传递**,用户空间用 `mmap` 后的虚拟地址读写 |
| 234 | +- **目标分辨率应与源配合**,旋转 90° 时宽高互换 |
| 235 | +- **格式转换**(如 RGB → YUV)由 G2D 硬件完成,源和目标 format 字段分别设置即可 |
| 236 | +- **调试时**,失败返回 `-1`,`errno` 记录具体原因,用 `perror()` 打印 |
0 commit comments