接前一篇文章:libdrm全解析三十四 ------ 源码全解析(31)
本文参考以下博文:
特此致谢!
前一篇文章讲解完了drmIoctl(DRM_IOCTL_MODE_MAP_DUMB)以及其封装函数drmModeMapDumbBuffer(),本篇文章继续讲解DRM一般流程的下一步。为了便于理解,再次贴出一般流程示例:
cpp
int main(int argc, char **argv)
{
/* open the drm device */
open("/dev/dri/card0");
/* get crtc/encoder/connector id */
drmModeGetResources(...);
/* get connector for display mode */
drmModeGetConnector(...);
/* create a dumb-buffer */
drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB);
/* bind the dumb-buffer to an FB object */
drmModeAddFB(...);
/* map the dumb buffer for userspace drawing */
drmIoctl(DRM_IOCTL_MODE_MAP_DUMB);
mmap(...);
/* start display */
drmModeSetCrtc(crtc_id, fb_id, connector_id, mode);
}
下一步是mmap。实际使用中调用的代码示例片段如下:
cpp
static void create_fb(int fd,uint32_t width, uint32_t height, uint32_t color ,struct framebuffer *buf)
{
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);
for (i = 0; i < (create.size / 4); i++)
vaddr[i] = color;
buf->vaddr=vaddr;
buf->handle=create.handle;
buf->size=create.size;
buf->fb_id=fb_id;
return;
}
create_fb(fd,connector->modes[0].hdisplay,connector->modes[0].vdisplay, 0xff0000, &buf[0]);
create_fb函数中,在上一步通过drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map)将dumb buffer与fd绑定,并根据handle返回offset后,在此调用了mmap函数,将通过offset得到的对应dumb buffer映射到用户空间。
在映射完成后,写入用户空间内存vaddr的访问(读写),实际上就是对于显存的访问了。
struct framebuffer是示例代码中自定义的结构,如下:
cpp
struct framebuffer{
uint32_t size;
uint32_t handle;
uint32_t fb_id;
uint32_t *vaddr;
};
至此,mmap()这一步就讲解完了。