gralloc1_perform具体在干什么
gralloc1_perform
会在特定场景下通过 ioctl
调用,执行 缓存 (cache) 管理 和 内存映射 操作,确保 CPU 和 GPU 之间的数据一致性。
📌 为什么需要对 cache 进行操作?
在 Android 系统中,CPU 和 GPU 通常共享 DDR 内存 (UMA 架构),但二者使用的缓存机制不同:
- CPU 使用 CPU Cache (L1/L2),访问速度快,但数据不会立刻写入内存。
- GPU 直接从 DDR 读取数据,通常不经过 CPU 缓存。
因此,如果 CPU 和 GPU 共享同一片内存,数据不一致(cache coherency)就会出现问题,必须通过缓存同步操作来避免:
- CPU 写入 -> GPU 读取:需要 flush (清空 CPU 缓存),确保 GPU 读到最新数据。
- GPU 写入 -> CPU 读取:需要 invalidate (无效化缓存),确保 CPU 读到最新数据。
📌 gralloc1_perform
中的 cache 操作
在 Android HAL 层,gralloc1_perform
是 gralloc
接口的扩展,支持执行各种自定义操作,缓存管理是其中一项常用功能。
常见的缓存操作主要包括以下几种:
操作 | 目的 | 使用场景 |
---|---|---|
GRALLOC1_PERFORM_FLUSH_CACHE | 清空 CPU 缓存,将数据写回内存 | CPU 写入的 buffer 需要供 GPU 读取时 |
GRALLOC1_PERFORM_INVALIDATE_CACHE | 无效化缓存,强制从内存中读取最新数据 | GPU 写入的数据,需要供 CPU 读取时 |
GRALLOC1_PERFORM_CLEAN_CACHE | 清除和同步缓存,确保多设备数据一致 | 需要在 CPU 和 DMA 设备(如 ISP、DSP)之间共享 |
GRALLOC1_PERFORM_SET_CACHE_MODE | 设置缓存模式(如 Write-Through) | 对特定 buffer 设置缓存策略,提升访问效率 |
📌 具体实现流程
当调用 gralloc1_perform
进行缓存管理时,内部通常会执行以下操作:
-
参数解析:根据
perform
请求类型,确定需要执行的缓存操作。 -
获取 buffer 对应的
fd
:通常使用 DMA-BUF 共享内存,gralloc
会为每个 buffer 维护一个文件描述符 (file descriptor, fd)。 -
通过
ioctl
调用 ION 驱动:执行底层缓存管理操作,常用的命令包括:ION_IOC_SYNC
:缓存同步的核心操作。ION_IOC_CLEAN_CACHES
:清空 CPU 缓存,确保数据写回内存。ION_IOC_INV_CACHES
:无效化缓存,确保从内存读取最新数据。ION_IOC_FLUSH_CACHES
:对缓存进行清理和刷新。
-
检查返回值:确保
ioctl
调用成功,错误时返回错误码。
📌 代码示例
以 GRALLOC1_PERFORM_FLUSH_CACHE
为例,执行缓存清理:
int gralloc1_perform(buffer_handle_t handle) {
int fd = get_buffer_fd(handle);
if (fd < 0) return -EINVAL;
struct ion_flush_data flushData = {
.fd = fd,
.offset = 0,
.length = get_buffer_size(handle),
};
struct ion_custom_data customData = {
.cmd = ION_IOC_CLEAN_CACHES,
.arg = (unsigned long)&flushData,
};
return ioctl(ion_fd, ION_IOC_CUSTOM, &customData);
}
📌 底层 ioctl 调用的关键结构体
缓存管理涉及到以下关键数据结构:
- 缓存同步数据 (
ion_flush_data
):
struct ion_flush_data {
int fd; // buffer 文件描述符
size_t offset; // 缓存同步起始偏移
size_t length; // 缓存同步的长度
unsigned long vaddr; // 映射的虚拟地址 (可选)
};
- 自定义 ioctl 调用 (
ion_custom_data
):
struct ion_custom_data {
unsigned int cmd; // ION 命令 (ION_IOC_CLEAN_CACHES 等)
unsigned long arg; // 命令的参数指针 (如 ion_flush_data)
};
📌 优化 cache 操作的注意事项
- 多线程与锁:缓存操作可能涉及多线程访问,通常需要加锁(如
mMutex
)防止竞争条件。 - 避免多余同步:不必要的缓存同步会导致性能下降,因此只在 CPU-GPU 数据交换时执行。
- IOCTL 调用开销:每次
ioctl
调用有一定的系统开销,需控制调用频率,避免影响帧率。
📌 总结
gralloc1_perform
在执行缓存操作时会通过ioctl
调用 ION 驱动,对共享内存 (DMA-BUF) 进行缓存同步。- 缓存操作的目的是解决 CPU 和 GPU 共享内存时的 数据不一致性问题,确保双方都能读到最新数据。
- 常用的缓存管理操作包括:
- Flush (清空缓存):CPU -> GPU 数据同步。
- Invalidate (无效缓存):GPU -> CPU 数据同步。
- Clean (清理缓存):确保 DMA 设备数据一致性。
- 该过程对 图像处理、AI 推理、视频解码 等涉及 GPU-CPU 数据交互 的场景尤为重要。