DRM应用编程一般流程


这一章主要对于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);
	}

}

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux DRM(Direct Rendering Manager)是一个内核子系统,用于管理图形、视频和显示硬件的驱动程序。通过使用Linux DRM开发人员可以编写应用程序来访问和控制这些硬件设备。 在Linux上进行DRM应用编程的步骤如下: 1. 确保你的系统支持DRM:确保你的Linux内核已经编译和安装了DRM子系统。大多数现代Linux发行版默认都包含了DRM支持,但是你可能需要检查一下是否需要安装额外的驱动程序或软件包。 2. 包含必要的头文件:在你的应用程序中,你需要包含一些必要的头文件来使用DRM函数和结构。其中最重要的是drm.h和drm_mode.h。你可以通过在你的代码中添加以下行来包含它们: ```c #include <drm.h> #include <drm_mode.h> ``` 3. 打开DRM设备:使用`drmOpen`函数打开DRM设备,并获取一个文件描述符。这个文件描述符将在接下来的操作中使用。例如: ```c int fd = drmOpen("drm", NULL); if (fd < 0) { // 处理错误 } ``` 4. 查询和配置显示模式:通过使用DRM函数来查询和配置显示模式。这包括获取可用的显示模式列表、选择一个合适的显示模式以及设置显示模式等。你可以使用`drmModeGetResources`、`drmModeGetConnector`和`drmModeSetCrtc`等函数来完成这些操作。 5. 分配和映射帧缓冲区:为显示分配和映射内存帧缓冲区。你可以使用`drmModeAddFB`和`drmModeMapDumb`函数来完成这些操作。 6. 绘制图形:使用你选择的图形库(如OpenGL或Vulkan)来进行绘制。你可以通过将这些图形库与DRM子系统集成来进行硬件加速的绘制。 7. 刷新显示:一旦你完成了图形的绘制,你可以使用`drmModePageFlip`函数将帧缓冲区切换到显示器上。这将使你的图形实际显示在屏幕上。 8. 清理和关闭:当你完成所有的绘制和显示后,记得释放分配的内存和关闭DRM设备。你可以使用`drmModeRmFB`和`drmClose`函数来完成这些操作。 这只是一个简单的概述,DRM应用编程涉及到更多的细节和复杂性。你可以参考Linux DRM子系统的文档和示例代码来获取更详细的信息,并根据你的需求进行适当的修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值