接前一篇文章:DRM全解析 —— CREATE_DUMB(1)
本文参考以下博文:
DRM驱动(三)之CREATE_DUMB
特此致谢!
上一回围绕libdrm与DRM在Linux内核中的接口:
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0),
进行了相关宏的展开。本文开始对于drm_mode_create_dumb_ioctl函数进行详解。drm_mode_create_dumb_ioctl函数在drivers/gpu/drm/drm_dumb_buffers.c中,代码如下:
int drm_mode_create_dumb_ioctl(struct drm_device *dev,void *data, struct drm_file *file_priv)
{return drm_mode_create_dumb(dev, data, file_priv);
}
drm_mode_create_dumb_ioctl函数只是一层简单封装,实际的工作交给了drm_mode_create_dumb函数。它就在上边,代码如下:
/*** DOC: overview** The KMS API doesn't standardize backing storage object creation and leaves it* to driver-specific ioctls. Furthermore actually creating a buffer object even* for GEM-based drivers is done through a driver-specific ioctl - GEM only has* a common userspace interface for sharing and destroying objects. While not an* issue for full-fledged graphics stacks that include device-specific userspace* components (in libdrm for instance), this limit makes DRM-based early boot* graphics unnecessarily complex.** Dumb objects partly alleviate the problem by providing a standard API to* create dumb buffers suitable for scanout, which can then be used to create* KMS frame buffers.** To support dumb objects drivers must implement the &drm_driver.dumb_create* and &drm_driver.dumb_map_offset operations (the latter defaults to* drm_gem_dumb_map_offset() if not set). Drivers that don't use GEM handles* additionally need to implement the &drm_driver.dumb_destroy operation. See* the callbacks for further details.** Note that dumb objects may not be used for gpu acceleration, as has been* attempted on some ARM embedded platforms. Such drivers really must have* a hardware-specific ioctl to allocate suitable buffer objects.*/int drm_mode_create_dumb(struct drm_device *dev,struct drm_mode_create_dumb *args,struct drm_file *file_priv)
{u32 cpp, stride, size;if (!dev->driver->dumb_create)return -ENOSYS;if (!args->width || !args->height || !args->bpp)return -EINVAL;/* overflow checks for 32bit size calculations */if (args->bpp > U32_MAX - 8)return -EINVAL;cpp = DIV_ROUND_UP(args->bpp, 8);if (cpp > U32_MAX / args->width)return -EINVAL;stride = cpp * args->width;if (args->height > U32_MAX / stride)return -EINVAL;/* test for wrap-around */size = args->height * stride;if (PAGE_ALIGN(size) == 0)return -EINVAL;/** handle, pitch and size are output parameters. Zero them out to* prevent drivers from accidentally using uninitialized data. Since* not all existing userspace is clearing these fields properly we* cannot reject IOCTL with garbage in them.*/args->handle = 0;args->pitch = 0;args->size = 0;return dev->driver->dumb_create(file_priv, dev, args);
}
在讲解此函数之前,先来看一下用户空间一般流程中调用此步骤的上下文:
create.width = width;create.height = height;create.bpp = 32;drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); //创建显存,返回一个handle
在libdrm全解析系列文章中讲过,在用户空间中通过
drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)
可以为显示创建buff。创建显示buf需要三个参数:
- width:图像宽度。
- height:图像高度。
- bpp:每个像素所占位(bit)数。
设置好以上参数后,将其放入数据结构struct drm_mode_create_dumb create中,并作为参数调用drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)传递给内核。内核根据请求创建显示buff后返回对应的handle赋值给handle、pitch、size给用户使用。
为了便于理解,再次贴出struct drm_mode_create_dumb的定义,在/usr/include/drm/drm_mode.h中,代码如下:
/* create a dumb scanout buffer */
struct drm_mode_create_dumb {__u32 height;__u32 width;__u32 bpp;__u32 flags;/* handle, pitch, size will be returned */__u32 handle;__u32 pitch;__u64 size;
};