转自: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
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。