转自:https://www.jianshu.com/p/f41f98a40455

DRM实例教程

DRM是一个显示驱动框架,也就是把功能封装成 open/close/ioctl 等标准接口,应用程序调用这些接口来驱动设备,显示数据。我们这里将从使用的角度来看看,怎么验证和使用DRM驱动。

DRM设备节点

DRM驱动会在/dev/dri下创建3个设备节点:

card0

controlD64

renderD128

libdrm库

DRM驱动,对用户空间,提供了专门的的调用库libdrm.so,用户空间通过该库可以间接的调用和使用驱动。

打开设备

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;

}

打开设备有专门的接口:drmOpen

检查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;

}

使用示例:

uint64_t has_dumb;

if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 ||

!has_dumb) {

fprintf(stderr, "drm device '%s' does not support dumb buffers\n",

node);

close(fd);

return -EOPNOTSUPP;

}

检索Resource

Resource的获取需要两次,第一次,获取数量大小,第二次才真正获取具体的Resource。具体看这个函数:

drmModeResPtr drmModeGetResources(int fd)

Resource结构封装:

struct drm_mode_card_res {

__u64 fb_id_ptr;

__u64 crtc_id_ptr;

__u64 connector_id_ptr;

__u64 encoder_id_ptr;

__u32 count_fbs;

__u32 count_crtcs;

__u32 count_connectors;

__u32 count_encoders;

__u32 min_width, max_width;

__u32 min_height, max_height;

};

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;

实例

/* retrieve resources */

int ret = drmModeGetResources(fd);

if (!res) {

fprintf(stderr, "cannot retrieve DRM resources (%d): %m\n",

errno);

return -errno;

}

获取Connector

_drmModeConnector描述结构:

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);

continue;

}

Encoder

Encoder的结构描述:

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;

}

crtc

CRTC结构描述:

struct crtc {

drmModeCrtc *crtc;

drmModeObjectProperties *props;

drmModePropertyRes **props_info;

drmModeModeInfo *mode;

};

typedef struct _drmModeCrtc {

uint32_t crtc_id;

uint32_t buffer_id; /**< FB id to connect to 0 = disconnect */

uint32_t x, y; /**< Position on the framebuffer */

uint32_t width, height;

int mode_valid;

drmModeModeInfo mode;

int gamma_size; /**< Number of gamma stops */

} drmModeCrtc, *drmModeCrtcPtr;

FrameBuffer

创建DUMB Buffer

ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);

if (ret < 0) {

fprintf(stderr, "cannot create dumb buffer (%d): %m\n",

errno);

return -errno;

}

添加FB

/* create framebuffer object for the dumb-buffer */

ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride,

dev->handle, &dev->fb);

if (ret) {

fprintf(stderr, "cannot create framebuffer (%d): %m\n",

errno);

ret = -errno;

goto err_destroy;

}

准备map

/* prepare buffer for memory mapping */

memset(&mreq, 0, sizeof(mreq));

mreq.handle = dev->handle;

ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);

if (ret) {

fprintf(stderr, "cannot map dumb buffer (%d): %m\n",

errno);

ret = -errno;

goto err_fb;

}

做map操作:

/* perform actual memory mapping */

dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED,

fd, mreq.offset);

if (dev->map == MAP_FAILED) {

fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n",

errno);

ret = -errno;

goto err_fb;

}

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);

}

绘制

static void modeset_draw(void)

{

uint8_t r, g, b;

bool r_up, g_up, b_up;

unsigned int i, j, k, off;

struct modeset_dev *iter;

srand(time(NULL));

r = rand() % 0xff;

g = rand() % 0xff;

b = rand() % 0xff;

r_up = g_up = b_up = true;

for (i = 0; i < 50; ++i) {

r = next_color(&r_up, r, 20);

g = next_color(&g_up, g, 10);

b = next_color(&b_up, b, 5);

for (iter = modeset_list; iter; iter = iter->next) {

for (j = 0; j < iter->height; ++j) {

for (k = 0; k < iter->width; ++k) {

off = iter->stride * j + k * 4;

*(uint32_t*)&iter->map[off] =

(r << 16) | (g << 8) | b;

}

}

}

usleep(100000);

}

}

具体的代码,可以参考how-to实例:

how-to代码实例

作者:夕月风链接:https://www.jianshu.com/p/f41f98a40455来源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

推荐文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。