接前一篇文章:DRM全解析 —— MAP_DUMB(1)
上一回围绕libdrm与DRM在Linux内核中的接口:
DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0),
进行了相关宏的展开。本文开始对于drm_mode_mmap_dumb_ioctl函数进行详解。drm_mode_mmap_dumb_ioctl函数在drivers/gpu/drm/drm_framebuffer.c中,代码如下:
/**
* drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* Allocate an offset in the drm device node's address space to be able to
* memory map a dumb buffer.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, negative errno on failure.
*/
int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
struct drm_mode_map_dumb *args = data;
if (!dev->driver->dumb_create)
return -ENOSYS;
if (dev->driver->dumb_map_offset)
return dev->driver->dumb_map_offset(file_priv, dev,
args->handle,
&args->offset);
else
return drm_gem_dumb_map_offset(file_priv, dev, args->handle,
&args->offset);
}
drm_mode_mmap_dumb_ioctl可没像drm_mode_addfb_ioctl和drm_mode_create_dumb_ioctl函数那样只是一层简单封装,实际的工作交给了drm_mode_mmap_dumb函数。人家压根儿就没用也没有drm_mode_mmap_dumb函数,而是自己完成了实际的工作。
在讲解此函数之前,先来看一下用户空间一般流程中调用此步骤(ioctl系统调用)的上下文:
struct drm_mode_create_dumb create = {};
struct drm_mode_map_dumb map = {};
uint32_t i;
uint32_t fb_id;
create.width = width;
create.height = height;
create.bpp = 32;
drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); //创建显存,返回一个handle
drmModeAddFB(fd, create.width, create.height, 24, 32, create.pitch,create.handle, &fb_id);
map.handle = create.handle;
drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map); //显存绑定fd,并根据handle返回offset
//通过offset找到对应的显存(framebuffer)并映射到用户空间
uint32_t *vaddr = mmap(0, create.size, PROT_READ | PROT_WRITE,MAP_SHARED, fd, map.offset);
在libdrm全解析系列文章以及DRM全解析 —— CREATE_DUMB系列文章中讲过,在用户空间中通过
drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)
最终在内核中在不同的显卡驱动相对应的函数中创建了一个dumb buffer对象(实际上是分配了struct drm_gem_object *gobj),返回的是与分配的struct drm_gem_object *gobj绑定的handle。
而在libdrm全解析系列文章以及DRM全解析 —— ADD_FB系列文章中讲过,drm_gem_object创建之后需要与一块drm_framebuffer进行绑定使用,因为最终刷图使用的是fb。因此,在用户空间中使用下面接口
drmModeAddFB(fd, create.width, create.height, 24, 32, create.pitch,create.handle, &fb_id)
创建drm_framebuffer并与之前创建的struct drm_gem_object *gobj进行绑定。
围绕DRM_IOCTL_MODE_MAP_DUMB宏的用户态和内核态上下调用流程,如下图所示: