因为camera要申请gralloc buf的缘故,打算仔细看看grallocbuf的原理,其实之前大概知道一些,这次梳理一下。因为部分接口封成了库,所以也没有去看相关代码,但是可以理解概念,知道gralloc是什么,怎么用就可以了。
Gralloc封装了用户层对帧缓冲区的操作接口,他可以申请图形缓冲区,然后将个缓冲区映射到应用程序上来,接下来就可以绘制界面。
主要是用于gpu和fb的操作,gpu用于分配图形缓冲,fb用于渲染帧缓冲。
但是rk从安卓7.1之后实现drm驱动,fb部分被删除了,应该是底层包含这部分功能。
先看看gralloc.h里面的结构
typedef struct gralloc_module_t {
struct hw_module_t common;//hal标准定义
//注册图形缓冲区,实际将一块图形缓冲区映射到一个进程的地址空间去
int (*registerBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);
int (*unregisterBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);
//可以锁定,防止冲突,这里可以锁定缓冲区特定区域
int (*lock)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
int (*unlock)(struct gralloc_module_t const* module,
buffer_handle_t handle);
int (*lock_ycbcr)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
struct android_ycbcr *ycbcr);
int (*lockAsync)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr, int fenceFd);
int (*unlockAsync)(struct gralloc_module_t const* module,
buffer_handle_t handle, int* fenceFd);
int (*lockAsync_ycbcr)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
struct android_ycbcr *ycbcr, int fenceFd);
void* reserved_proc[3];
} gralloc_module_t;
默认的代码在gralloc_module_t外面又封装了一层。保存了framebuffer的相关信息
struct private_module_t {
gralloc_module_t base;
private_handle_t* framebuffer;
uint32_t flags;
uint32_t numBuffers;
uint32_t bufferMask;
pthread_mutex_t lock;
buffer_handle_t currentBuffer;
int pmem_master;
void* pmem_master_base;
struct fb_var_screeninfo info;
struct fb_fix_screeninfo finfo;
float xdpi;
float ydpi;
float fps;
};
但是rk应该是实现了
struct drm_module_t {
gralloc_module_t base;
pthread_mutex_t mutex;
/** gralloc_drm_device. */
struct gralloc_drm_t *drm;
#ifdef __cplusplus
/* default constructor */
drm_module_t();
#endif
#if RK_DRM_GRALLOC
volatile int32_t refcount;
#endif
}
这个gralloc实现就相对更简单了。
Hal部分rk的代码在\hardware\rockchip\libgralloc下面
在camera 部分调用加载模块的函数如下:
返回的alloc_device_是alloc_device_t结构,描述gralloc,里面有alloc和free函数。
加载模块的时候调用drm_module_t::drm_module_t()函数赋值gralloc_module_t里面的methods->open函数以及里面register和lock这些函数。
gralloc_open 执行的是模块的open函数
static inline int gralloc_open(const struct hw_module_t* module,
struct alloc_device_t** device) {
return module->methods->open(module,
GRALLOC_HARDWARE_GPU0, TO_HW_DEVICE_T_OPEN(device));
}
Open函数调用drm_mod_open到drm_mod_open_gpu0函数。里面先执行
Drm_init()。这个初始化内容是创建gralloc_drm_t设备。打开系统属性vendor.ggralloc.drm.device里面记录的drm设备路径。
然后调用gralloc_drm_drv_create_for_rockchip
struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_rockchip(int fd)
{
……
rk_drv = new rk_driver_of_gralloc_drm_device_t;
……
//这个函数实现在libdrm_rockchip.so,竟然不公开。。。
rk_drv->rk_drm_dev = rockchip_device_create(fd);
……
//初始化 'rk_drv' 中的 rk_drm_adapter.
rk_drm_adapter_init(rk_drv);
……
//赋值相关函数
rk_drv->fd_of_drm_dev = fd;
rk_drv->base.destroy = drm_gem_rockchip_destroy;
rk_drv->base.alloc = drm_gem_rockchip_alloc;
rk_drv->base.free = drm_gem_rockchip_free;
rk_drv->base.map = drm_gem_rockchip_map;
rk_drv->base.unmap = drm_gem_rockchip_unmap;
return &rk_drv->base;
}
然后赋值alloc和free函数,分别为
alloc->alloc = drm_mod_alloc_gpu0;
alloc->free = drm_mod_free_gpu0;
open整个过程如上面所说,初始化drm设备,和对应的操作函数。
初始化的时候要注册buffer
status_t CameraBuffer::init(const camera3_stream_buffer *aBuffer, int cameraId)
调用int ret = registerBuffer();//向gralloc 模块注册
mGbmBufferManager->Register(mHandle);
int CameraBufferManagerImpl::Register(buffer_handle_t buffer) {
执行gm_module_->registerBuffer(gm_module_, buffer);
注册buffer。
调用drm_mod_register_buffer—-> gralloc_drm_handle_register- validate_handle
主要调用drm_gem_rockchip_alloc 制作import工作
申请buffer的函数
int CameraBufferManagerImpl::AllocateGrallocBuffer(size_t width,
size_t height,
uint32_t format,
uint32_t usage,
buffer_handle_t* out_buffer,
uint32_t* out_stride) {
……
int ret = alloc_device_->alloc(alloc_device_, width, height,
format, usage, out_buffer,
reinterpret_cast<int*>(out_stride));
}
这样会调用到gralloc的alloc函数
static int drm_mod_alloc_gpu0(alloc_device_t *dev,
int w, int h, int format, int usage,
buffer_handle_t *handle, int *stride)
{
……
bo = gralloc_drm_bo_create(dmod->drm, w, h, format, usage);
*handle = gralloc_drm_bo_get_handle(bo, &byte_stride);
gralloc_drm_handle_get_format(*handle, &actual_format);
bpp = gralloc_drm_get_bpp(actual_format);
}
再看
struct gralloc_drm_bo_t *gralloc_drm_bo_create(struct gralloc_drm_t *drm,
int width, int height, int format, int usage)
{
……
//先创建handle
handle = create_bo_handle(width, height, format, usage);
bo = drm->drv->alloc(drm->drv, handle);
……
return bo;
}
drm->drv->alloc 执行的是drm_gem_rockchip_alloc
这个函数特别长
大概是先判断格式获取stride,然后alloc一个rockchip_buffer结构体,这个是buffer的封装结构。接着判断如果prime_fd判断是否已经分配buffer,分配就就调用drmPrimeFDToHandle ,import到当前进程。如果buffer没有分配,则分配,调用rk_drm_adapter_create_rockchip_bo分配dma buffer.实际说通过rk_drm_adapter_get_gem_handle,返回创建到handle(gem_obj)。
实际上由于当前部分函数没有源码,说不详细,但是知道申请的大概是alloc函数是获取bpp,宽高,然后调用DRM_IOCTL_MODE_CREATE_DUMB这条ioctl。然后调用DRM_IOCTL_MODE_MAP_DUMB 来map这段内存。对于camera就只要知道申请,import就可以了,camera申请了gralloc buffer用做中间的处理buffer,上层是surface,会转换成gralloc buffer,然后在hal中import过来。