常见Soc平台图形内存管理学习笔记
硬件编解码、硬件图像scale等过程,是在专有的硬件单元里进行,其使用的内存也是专有的内存,这种内存多是SoC中图形内存。如此方便与硬件加速图形渲染、图像显示、硬件图像加速处理等功能相交互。
上述过程在使用图形内存时,自然需要使用对应的图形内存管理API。常见的图形内存管理API有以下几种:
1,DRM
主要是只其中的内存管理部分,包括dumb-buffer和GEM(Graphics Execution Manager)的两种类型接口。具体的驱动根据芯片支持情况做实现,并且为用户态提供相应的API。
1.1 dumb-buffer
其较为通用,分配之后可以做映射处理,获取一个用户态的指针,后续可据此在向图形内存中写入数据,但此种方式不能保证图形内存中数据缓存的一致性。其一般使用流程是
a) open() drm 设备节点,多是 /dev/dri/card0 等,得到设备操作fd句柄
b) ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, )创建一个 dumb-buffer ,获取buffer句柄。需要指定 宽高/BPP 等参数
c) ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, ) 根据该buffer对象的伪offset
d) mmap(, offset) 将该buffer对象映射到用户态,获得一个指针,后续就可以向其中写入数据了
e) ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, ) 销毁 dumb-buffer 对象
1.2 GEM buffer
除了dumb-buffer所提供的功能外,对于创建和读写操作,厂商多是额外提供专有的API来进行,如此完成读写的同时,可以在其中进行缓存一致性的操作;而且GEM可以为每个Buffer对象分配一个32bit的名字,用于跨进程传递。
其使用流程一般是,以 Intel i915 系列平台威力
a) open() drm 设备节点,多是 /dev/dri/card0 等,得到设备操作fd句柄
b) ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, struct drm_i915_gem_create) 创建一个 GEM buffer对象,获取其 handle,简单指定尺寸即可。
c) ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, struct drm_i915_gem_pread)/ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)进行读写,可以保证缓存一致性
ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, struct drm_i915_gem_mmap) 获取一个用户态的映射指针,不保证缓存一致性
d) ioctl(fd, DRM_IOCTL_GEM_CLOSE, struct drm_gem_close) 释放刚才的 GEM buffer对象
获取GEM Buffer对象名,以及跨进程传递流程如下
a) ioctl(fd, DRM_IOCTL_GEM_FLINK, struct drm_gem_flink) 获取 GEM Buffer 的名字
b) ioctl(fd, DRM_IOCTL_GEM_OPEN, struct drm_gem_open) 根据名字,获取对应 GEM Buffer对象在当前进程内的 handle
GEM Buffer对象实现是引用计数的,当所有用户态handle全部关闭时,其才被真正释放。
2,ION
ION是Google提出的一套纯粹的图形内存管理API,在现在Android系统中支持的比较广泛。其使用方式和GEM有些类似,也可以跨进程传递Buffer句柄,来将不同的图形任务分散到不同的进程中进行(Android系统实际上就是这么做的)
其基本使用流程为
a) open() drm 设备节点,多是 /dev/ion,得到设备操作fd句柄
b) ioctl(fd, ION_IOC_ALLOC, struct ion_allocation_data) 分配,返回 struct ion_handle,简单指定尺寸信息即可。
b) ioctl(fd, ION_IOC_FREE, struct ion_handle_data) 释放
c) ioctl(fd, ION_IOC_SHARE, struct ion_fd_data)/ioctl(fd, ION_IOC_MAP, struct ion_fd_data) 返回 ION Buffer对象的 fd 表示,
后续可用此 fd 调用 mmap() 获取用户天指针,或跨进程传递
d) ioctl(fd, ION_IOC_IMPORT, struct ion_fd_data) 根据别处提供的fd,获取本地的 struct ion_handle
e) ioctl(fd, ION_IOC_SYNC, struct ion_fd_data) 对 ION Buffer做缓存刷新,保证一致性。
3, 厂商私有的API
3.1 Allwinner A20平台,其硬件编解码单元cedar,在用户态的提供的图形内存的接口就是一套私有的API,具体请见 https://github.com/allwinner-zh/media-codec/tree/master/sunxi-cedarx/SOURCE/common
其提供的API具体访问的设备节点是 /dev/cedar_dev, 详情见 ve.h/ve_alloc.h 中的API和对应实现。
3.2 Intel HD系列集成GPU平台,其图形内存的管理API是在libva中,具体硬件访问是在 libva 的用户态后端 vaapi-driver 中进行的。
其中使用 VASurface 名词表示图形内存对象,其创建是需要制定 宽高/像素格式 基本参数。其使用时需要先获取一个 VADisplay 对象,而获取该对象的入口在 Android/DRM/Wayland 不同的显示后端上有不同入口。详细见libva 的API说明。
[update 2020/3/24] libva是 VA-API的实现,背后依赖各个厂家提供的驱动。VA-API如其名(Video Acceleration),是硬件视频加速处理的一套API规范,并非Intel专有,ADM/Nvidia平台上其实也有相应的支持。libva图形内存管理的工作是用其他组来实现的,比如DRM/GLX/XWindow。
3.3 UMP(Unified Memory Provider)
是ARM平台下一套内存管理机制接口。