目录
1. drm_mode_addfb2
2. drm_internal_framebuffer_create
3. drm_fb_cma_create->drm_gem_fb_create->drm_gem_fb_create_with_funcs
4. drm_gem_fb_alloc
4.1 drm_helper_mode_fill_fb_struct
4.2 drm_framebuffer_init
5. 调用流程图
书接上回,使用drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)接口创建了一块内存放在了gem cma的对象里。
gem obj创建之后需要与一块drm_framebuffer进行绑定使用,因为最终刷图使用的是fb。使用下面接口会创建drm_framebuffer并与上节创建的gem obj进行绑定。
目前使用较多的就是drm_mode_addfb2接口,该接口完成了下面的功能。

1. drm_mode_addfb2
int drm_mode_addfb2(struct drm_device *dev,
		    void *data, struct drm_file *file_priv)
{
	struct drm_mode_fb_cmd2 *r = data;
	struct drm_framebuffer *fb;
	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EINVAL;
	fb = drm_internal_framebuffer_create(dev, r, file_priv);
	if (IS_ERR(fb))
		return PTR_ERR(fb);
	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
	r->fb_id = fb->base.id;
	/* Transfer ownership to the filp for reaping on close */
	mutex_lock(&file_priv->fbs_lock);
	list_add(&fb->filp_head, &file_priv->fbs);
	mutex_unlock(&file_priv->fbs_lock);
	return 0;
} 
drm_mode_addfb2主要做了三件大事:
(1)调用drm_internal_framebuffer_create创建一个drm_framebuffer。
(2)把drm_framebuffer的struct drm_mode_object的ID返回给应用。
(3)加到file_priv的fbs链表中。
下面我们看一下函数drm_internal_framebuffer_create。
2. drm_internal_framebuffer_create
struct drm_framebuffer *
drm_internal_framebuffer_create(struct drm_device *dev,
				const struct drm_mode_fb_cmd2 *r,
				struct drm_file *file_priv)
{
    ........
	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
	if (IS_ERR(fb)) {
		DRM_DEBUG_KMS("could not create framebuffer\n");
		return fb;
	}
	return fb;
} 
检查参数,然后调用dev->mode_config.funcs->fb_create(dev, file_priv, r),可以自己实现,也可以使用内核现成的drm_fb_cma_create。
3. drm_fb_cma_create->drm_gem_fb_create->drm_gem_fb_create_with_funcs
struct drm_framebuffer *
drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
			     const struct drm_mode_fb_cmd2 *mode_cmd,
			     const struct drm_framebuffer_funcs *funcs)
{
	const struct drm_format_info *info;
	struct drm_gem_object *objs[4];
	struct drm_framebuffer *fb;
	int ret, i;
	info = drm_get_format_info(dev, mode_cmd);
	if (!info)
		return ERR_PTR(-EINVAL);
	for (i = 0; i < info->num_planes; i++) {
		unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
		unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
		unsigned int min_size;
		objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
		if (!objs[i]) {
			DRM_DEV_ERROR(dev->dev, "Failed to lookup GEM\n");
			ret = -ENOENT;
			goto err_gem_object_put;
		}
		min_size = (height - 1) * mode_cmd->pitches[i]
			 + width * info->cpp[i]
			 + mode_cmd->offsets[i];
		if (objs[i]->size < min_size) {
			// DRM_DEV_ERROR(dev->dev, "objs %d Size(%d %d) error\n",
			// 	i, objs[i]->size, min_size);
			drm_gem_object_put_unlocked(objs[i]);
			ret = -EINVAL;
			goto err_gem_object_put;
		}
	}
	fb = drm_gem_fb_alloc(dev, mode_cmd, objs, i, funcs);
	if (IS_ERR(fb)) {
		ret = PTR_ERR(fb);
		DRM_DEV_ERROR(dev->dev, "alloc error %d\n", ret);
		goto err_gem_object_put;
	}
	return fb;
err_gem_object_put:
	for (i--; i >= 0; i--)
		drm_gem_object_put_unlocked(objs[i]);
	return ERR_PTR(ret);
} 
(1)通过应用提供的handle,使用drm_gem_object_lookup找到上次创建的gem obj。
(2)调用drm_gem_fb_alloc,分配一个drm_framebuffer,将gem obj赋值给framebuffer中的obj。
4. drm_gem_fb_alloc
static struct drm_framebuffer *
drm_gem_fb_alloc(struct drm_device *dev,
		 const struct drm_mode_fb_cmd2 *mode_cmd,
		 struct drm_gem_object **obj, unsigned int num_planes,
		 const struct drm_framebuffer_funcs *funcs)
{
	struct drm_framebuffer *fb;
	int ret, i;
	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
	if (!fb)
		return ERR_PTR(-ENOMEM);
	drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
	for (i = 0; i < num_planes; i++)
		fb->obj[i] = obj[i];
	ret = drm_framebuffer_init(dev, fb, funcs);
	if (ret) {
		DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n",
			      ret);
		kfree(fb);
		return ERR_PTR(ret);
	}
	return fb;
} 
4.1 drm_helper_mode_fill_fb_struct
void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
				    struct drm_framebuffer *fb,
				    const struct drm_mode_fb_cmd2 *mode_cmd)
{
	int i;
	fb->dev = dev;
	fb->format = drm_get_format_info(dev, mode_cmd);
	fb->width = mode_cmd->width;
	fb->height = mode_cmd->height;
	for (i = 0; i < 4; i++) {
		fb->pitches[i] = mode_cmd->pitches[i];
		fb->offsets[i] = mode_cmd->offsets[i];
	}
	fb->modifier = mode_cmd->modifier[0];
	fb->flags = mode_cmd->flags;
} 
将应用传入的长,宽,format,pitch,flag等填充framebuffer结构体。
4.2 drm_framebuffer_init
int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
			 const struct drm_framebuffer_funcs *funcs)
{
	int ret;
	if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
		return -EINVAL;
	INIT_LIST_HEAD(&fb->filp_head);
	fb->funcs = funcs;
	ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
				    false, drm_framebuffer_free);
	if (ret)
		goto out;
	mutex_lock(&dev->mode_config.fb_lock);
	dev->mode_config.num_fb++;
	list_add(&fb->head, &dev->mode_config.fb_list);
	mutex_unlock(&dev->mode_config.fb_lock);
	drm_mode_object_register(dev, &fb->base);
out:
	return ret;
} 
相关字段填充完成后会将fb添加进dev->mode_config.fb_list便于后面使用的时候通过id进行查找, drm的组件都是通过dev->mode_config中的链表进行管理的,只要拿到mode_config就可以拿到drm相关信息。
至此drm_framebuffer已经创建完毕。通过r->fb_id = fb->base.id;将fb_id返回给用户。
5. 调用流程图




















