DRM驱动(三)之CREATE_DUMB
我会根据我们如何创建一个drm的buf呢,或者你已经知道可以使用drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)可以为显示创建buff,但此函数在内核又做了什么呢?下面一起学习一下内核如何为应用创建显存。
上节讲到显示处理器会将一块含有图像数据的memory进行处理后送到下一级。后面几节我会根据龙哥的《最简单的DRM应用程序》一步一步分析用户调用的接口在drm驱动中有怎么样的处理。
DRM驱动的显存由GEM(Graphics execution management)管理。
我会根据我们如何创建一个drm的buf呢,或者你已经知道可以使用
drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)
可以为显示创建buff,但此函数在内核又做了什么呢?下面一起学习一下内核如何为应用创建显存。
user space
创建显示buf需要三个参数
- width //图像宽度
- height //图像高度
- bpp //每个像素占用bit数
将以上参数放入数据结构struct drm_mode_create_dumb create中,并作为参数调用drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)后内核返回对应的handle赋值给handle,patch给用户使用;至于为什么会返回handle,后面介绍kernel部分的时候再说。
kernel space
在drm_ioctl.c中搜索DRM_IOCTL_MODE_CREATE_DUMB可知会调用drm_mode_create_dumb_ioctl
而此函数会调用drm_driver中注册的dev->driver->dumb_create(file_priv, dev, args)。
为了方便大家理解,拿出来了imx的部分代码:
此回调函数可以由厂商根据需要自己实现,这里采用默认的创建dump buf函数。
int drm_gem_cma_dumb_create(struct drm_file *file_priv,
struct drm_device *drm, struct drm_mode_create_dumb *args)
{
struct drm_gem_cma_object *cma_obj;
args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
args->size = args->pitch * args->height;
cma_obj = drm_gem_cma_create_with_handle(file_priv, drm, args->size, &args->handle);
return PTR_ERR_OR_ZERO(cma_obj);
}
此函数的目的有两个
- 计算patch,返回用户
- 创建对象drm_gem_cma_object,因为其中包括分配内存的物理地址和虚拟地址;还包含一个重要的结构drm_gem_object
static struct drm_gem_cma_object *
drm_gem_cma_create_with_handle(struct drm_file *file_priv,
struct drm_device *drm, size_t size,
uint32_t *handle)
{
struct drm_gem_cma_object *cma_obj;
struct drm_gem_object *gem_obj;
int ret;
cma_obj = drm_gem_cma_create(drm, size);
gem_obj = &cma_obj->base;
ret = drm_gem_handle_create(file_priv, gem_obj, handle);
return cma_obj;
}
以上代码删除了错误处理
drm_gem_cma_create有两个作用
- 创建drm_gem_cma_object对象并初始化其中的drm_gem_object
- 使用dma_alloc_wc分配内存并将物理地址存入paddr,虚拟地址存入vaddr
struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
size_t size)
{
struct drm_gem_cma_object *cma_obj;
size = round_up(size, PAGE_SIZE);
cma_obj = __drm_gem_cma_create(drm, size);
if (IS_ERR(cma_obj))
return cma_obj;
cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr,
GFP_KERNEL | __GFP_NOWARN);
return cma_obj;
}
drm_gem_handle_create主要使用idr_alloc将drm_gem_object对象添加到file_priv->object_idr,并返回handle。
idr_alloc:是为了使用一个id与一个obj绑定。这样就可以通过id找到对应obj。这里将handle与分配的gem_object进行绑定,后面通过handle可以找到gem_object进而找到cma_object获取到物理地址或者虚拟地址
drm_gem_handle_create->drm_gem_handle_create_tail
int drm_gem_handle_create_tail(struct drm_file *file_priv,
struct drm_gem_object *obj,
u32 *handlep)
{
struct drm_device *dev = obj->dev;
u32 handle;
int ret;
idr_preload(GFP_KERNEL);
ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);
idr_preload_end();
handle = ret;
ret = drm_vma_node_allow(&obj->vma_node, file_priv);
if (ret)
goto err_remove;
if (dev->driver->gem_open_object) {
ret = dev->driver->gem_open_object(obj, file_priv);
if (ret)
goto err_revoke;
}
*handlep = handle;
return 0;
}
到这里就完成了显示内存的获取。返回的handle和patch将在后面用到。
我也画了一个流程图,有需要的可以自取https://gitee.com/chaochao-feng/drm_driver.git
更多推荐
所有评论(0)