这一章主要对于drm应用编程的一般流程做一个简单的总结,请勿根据此流程进行实际操作
1.打开设备
DRM驱动会在/dev/dri下创建3个设备节点,用户空间可以使用libdrm.so
提供的库函数来进行drm的应用开发
card0
controlD64
renderD128
使用:
int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
if (fd < 0) {
ret = -errno;
fprintf(stderr, "cannot open '%s': %m\n", node);
return ret;
}
2.检查drm的能力
drm能力可以通过drmGetCap接口获取,用drm_get_cap结构体描述为:
/** DRM_IOCTL_GET_CAP ioctl argument type */
struct drm_get_cap {
__u64 capability;
__u64 value;
};
int drmGetCap(int fd, uint64_t capability, uint64_t *value)
{
struct drm_get_cap cap;
int ret;
memclear(cap);
cap.capability = capability;
ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
if (ret)
return ret;
*value = cap.value;
return 0;
}
使用:
int drm_check_capability(int fd)
{
uint64_t flag;
if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &flag) < 0 || !flag) {
perror("this drm device does not support dumb buffer");
return -1;
}
return 0;
}
3.检查Resource
用到的函数为
drmModeResPtr drmModeGetResources(int fd)
结构为:
typedef struct _drmModeRes {
int count_fbs;
uint32_t *fbs;
int count_crtcs;
uint32_t *crtcs;
int count_connectors;
uint32_t *connectors;
int count_encoders;
uint32_t *encoders;
uint32_t min_width, max_width;
uint32_t min_height, max_height;
} drmModeRes, *drmModeResPtr;
实例:
res = drmModeGetResources(fd);
if (!res) {
perror("cannot get drm resources ,err ");
return -errno;
}
4.获取Connector
结构描述:
typedef struct _drmModeConnector {
uint32_t connector_id;
uint32_t encoder_id; /**< Encoder currently connected to */
uint32_t connector_type;
uint32_t connector_type_id;
drmModeConnection connection;
uint32_t mmWidth, mmHeight; /**< HxW in millimeters */
drmModeSubPixel subpixel;
int count_modes;
drmModeModeInfoPtr modes;
int count_props;
uint32_t *props; /**< List of property ids */
uint64_t *prop_values; /**< List of property values */
int count_encoders;
uint32_t *encoders; /**< List of encoder ids */
} drmModeConnector, *drmModeConnectorPtr;
示例:
drmModeConnector *conn = drmModeGetConnector(fd, res->connectors[i]);
if (!conn) {
fprintf(stderr, "cannot retrieve DRM connector %u:%u (%d): %m\n",
i, res->connectors[i], errno);
s continue;
}
5.获取Enconder
Enconder结构描述为:
typedef struct _drmModeEncoder {
uint32_t encoder_id;
uint32_t encoder_type;
uint32_t crtc_id;
uint32_t possible_crtcs;
uint32_t possible_clones;
} drmModeEncoder, *drmModeEncoderPtr;
示例:
if (conn->encoder_id)
{
drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoder_id);
}
drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
{
struct drm_mode_get_encoder enc;
drmModeEncoderPtr r = NULL;
memclear(enc);
enc.encoder_id = encoder_id;
if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc))
return 0;
if (!(r = drmMalloc(sizeof(*r))))
return 0;
r->encoder_id = enc.encoder_id;
r->crtc_id = enc.crtc_id;
r->encoder_type = enc.encoder_type;
r->possible_crtcs = enc.possible_crtcs;
r->possible_clones = enc.possible_clones;
return r;
}
6.创建Framebuffer
需要用到的结构体表示为:
/* 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;
};
/* set up for mmap of a dumb scanout buffer */
struct drm_mode_map_dumb {
/** Handle for the object being mapped. */
__u32 handle;
__u32 pad;
/**
* Fake offset to use for subsequent mmap call
*
* This is a fixed-size type for 32/64 compatibility.
*/
__u64 offset;
};
struct drm_mode_destroy_dumb {
__u32 handle;
};
int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
uint32_t *buf_id)
{
struct drm_mode_fb_cmd f;
int ret;
memclear(f);
f.width = width;
f.height = height;
f.pitch = pitch;
f.bpp = bpp;
f.depth = depth;
f.handle = bo_handle;
if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB, &f)))
return ret;
*buf_id = f.fb_id;
return 0;
}
创建DUMB Buffer
struct drm_mode_create_dumb creq;
uint32_t *fb_id;
rval = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
if (rval < 0) {
printf("%s-->create dumb buffer error:%m\n", __func__);
return -errno;
创建framebuffer对象
/* create framebuffer object for the dumb-buffer */
rval = drmModeAddFB(fd, crep.width, crep.height, 24, crep.bpp,
crep.width * bpp/8, crep.fb_handle, &fb_id);
if (rval < 0) {
printf("%s-->create framebuffer error: %m\n", __func__);
return rval;
}
进行mmap
struct drm_mode_map_dumb mreq;
/* 准备内存映射:获取dumb缓冲区的mmap偏移量 */
rval = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (rval) {
printf("%s-->MODE_MAP_DUMBr error:%m\n", __func__);
return -errno;
}
进行内存映射:
/* 内存映射 */
kms->fmt->vaddr = mmap(0, kms->fmt->size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, mreq.offset);
if (MAP_FAILED == kms->fmt->vaddr) {
printf("%s-->cannot mmap dumb buffer error:%m\n", __func__);
return -errno;
}
memset(kms->fmt->vaddr, 0, kms->fmt->size);
7.准备CRTC
drmModeGetCrtc,drmModeSetCrtc函数
drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
{
struct drm_mode_crtc crtc;
drmModeCrtcPtr r;
memclear(crtc);
crtc.crtc_id = crtcId;
if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc))
return 0;
/*
* return
*/
if (!(r = drmMalloc(sizeof(*r))))
return 0;
r->crtc_id = crtc.crtc_id;
r->x = crtc.x;
r->y = crtc.y;
r->mode_valid = crtc.mode_valid;
if (r->mode_valid) {
memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo));
r->width = crtc.mode.hdisplay;
r->height = crtc.mode.vdisplay;
}
r->buffer_id = crtc.fb_id;
r->gamma_size = crtc.gamma_size;
return r;
}
int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
uint32_t x, uint32_t y, uint32_t *connectors, int count,
drmModeModeInfoPtr mode)
{
struct drm_mode_crtc crtc;
memclear(crtc);
crtc.x = x;
crtc.y = y;
crtc.crtc_id = crtcId;
crtc.fb_id = bufferId;
crtc.set_connectors_ptr = VOID2U64(connectors);
crtc.count_connectors = count;
if (mode) {
memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
crtc.mode_valid = 1;
}
return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
}
示例:
kms.old_crtc = drmModeGetCrtc(fd, kms.crtc_id);
err = drmModeSetCrtc(fd, kms.crtc_id, kms.fb_id, 0, 0,
&kms.conn_id, 1, &kms.mode);
if (err < 0) {
printf("cannot set CRTC for connector \n");
return err;
}
8.画图
void drm_draw_background(void)
{
int i, k;
int color[] = {0xff0000, 0xffff00, 0x00ff00}; //红、黄、绿
for (k = 0; k < 3; k++) {
for (i = 0; i < (kms.fb_size / 4); i++)
kms.fb_map[i] = color[k];
sleep(2);
}
}