drm单个framebuffer显示

Drm 单个buff显示

这章介绍drm的部分的函数和结构体,实现单个frambuffer的显示

drm buff相关结构体

struct buffer object

struct buffer_object {
	unsigned int width;
	unsigned int height;
	unsigned int pitch;		//图片每一行数据所占字节数 例800*1280 rgb  ->800*3
	unsigned int handle;	//gem 缓冲区fd
	unsigned int size;
	unsigned int *vaddr;
	unsigned int fb_id;		//framebuffer创建的bufid
};

struct drm_mode_create_dumb

struct drm_mode_create_dumb {
	//user fill in
	__u32 height;
	__u32 width;
	__u32 bpp;		//像素位深
	__u32 flags;	//current unused
	//kernel return fill in
	__u32 handle;	//gem 缓冲区fd
	__u32 pitch;	//图片每一行数据所占字节数 例800*1280 rgb  ->800*3
	__u64 size;		//(height * pitch + width) * bpp / 4
};

struct drm_mode_map_dumb

struct drm_mode_map_dumb {
	__u32 handle;		//申请的gem handle
	__u32 pad;			//unused

	__u64 offset;		//用于mmap的偏移大小
};

通过ioctl来创建获取dumb buf

/* 创建一个dumb buffer
ioctl can be used to create a dumb buffer. The kernel will return a 32bit handle
that can be used to manage the buffer with the DRM API. You can create framebuffers with
*/
DRM_IOCTL_MODE_CREATE_DUMB
/*获取dumb内存映射偏移值
ioctl requests the DRM subsystem to prepare the buffer for memory-mapping and returns a
fake-offset that can be used with*/
DRM_IOCTL_MODE_MAP_DUMB    

drmModeRes

typedef struct _drmModeRes {
    int count_fbs;		//当前申请的framebuffer的数量
    uint32_t *fbs;		

    int count_crtcs;	//可用的crtcs配置
    uint32_t *crtcs;

    int count_connectors;	//可用的连接器connectors
    uint32_t *connectors;

    int count_encoders;		//可用的编码器encoders 
    uint32_t *encoders;

    uint32_t min_width, max_width;
    uint32_t min_height, max_height;
} drmModeRes, *drmModeResPtr;

drm相关操作函数

drmSetClientCap

drm设置客户端属性

/** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
struct drm_set_client_cap {
	__u64 capability;
	__u64 value;
};
/**
 * DRM_CLIENT_CAP_STEREO_3D
 *
 * if set to 1, the DRM core will expose the stereo 3D capabilities of the
 * monitor by advertising the supported 3D layouts in the flags of struct
 * drm_mode_modeinfo.
 */
#define DRM_CLIENT_CAP_STEREO_3D	1

/**
 * DRM_CLIENT_CAP_UNIVERSAL_PLANES
 *
 * If set to 1, the DRM core will expose all planes (overlay, primary, and
 * cursor) to userspace.
 */
#define DRM_CLIENT_CAP_UNIVERSAL_PLANES  2

/**
 * DRM_CLIENT_CAP_ATOMIC
 *
 * If set to 1, the DRM core will expose atomic properties to userspace
 */
#define DRM_CLIENT_CAP_ATOMIC	3

int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
{
    struct drm_set_client_cap cap;

    memclear(cap);
    cap.capability = capability;
    cap.value = value;

    return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
}

drmModeGetResources

获取card的所有资源信息

drmModeResPtr drmModeGetResources(int fd)
{
	struct drm_mode_card_res res, counts;
	drmModeResPtr r = 0;

retry:
	memclear(res);
	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
		return 0;

	counts = res;

	if (res.count_fbs) {
		res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
		if (!res.fb_id_ptr)
			goto err_allocs;
	}
	if (res.count_crtcs) {
		res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
		if (!res.crtc_id_ptr)
			goto err_allocs;
	}
	if (res.count_connectors) {
		res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t)));
		if (!res.connector_id_ptr)
			goto err_allocs;
	}
	if (res.count_encoders) {
		res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
		if (!res.encoder_id_ptr)
			goto err_allocs;
	}

	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
		goto err_allocs;

	/* The number of available connectors and etc may have changed with a
	 * hotplug event in between the ioctls, in which case the field is
	 * silently ignored by the kernel.
	 */
	if (counts.count_fbs < res.count_fbs ||
	    counts.count_crtcs < res.count_crtcs ||
	    counts.count_connectors < res.count_connectors ||
	    counts.count_encoders < res.count_encoders)
	{
		drmFree(U642VOID(res.fb_id_ptr));
		drmFree(U642VOID(res.crtc_id_ptr));
		drmFree(U642VOID(res.connector_id_ptr));
		drmFree(U642VOID(res.encoder_id_ptr));

		goto retry;
	}

	/*
	 * return
	 */
	if (!(r = drmMalloc(sizeof(*r))))
		goto err_allocs;

	r->min_width     = res.min_width;
	r->max_width     = res.max_width;
	r->min_height    = res.min_height;
	r->max_height    = res.max_height;
	r->count_fbs     = res.count_fbs;
	r->count_crtcs   = res.count_crtcs;
	r->count_connectors = res.count_connectors;
	r->count_encoders = res.count_encoders;

	r->fbs        = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
	r->crtcs      = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
	r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t));
	r->encoders   = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));
	if ((res.count_fbs && !r->fbs) ||
	    (res.count_crtcs && !r->crtcs) ||
	    (res.count_connectors && !r->connectors) ||
	    (res.count_encoders && !r->encoders))
	{
		drmFree(r->fbs);
		drmFree(r->crtcs);
		drmFree(r->connectors);
		drmFree(r->encoders);
		drmFree(r);
		r = 0;
	}

err_allocs:
	drmFree(U642VOID(res.fb_id_ptr));
	drmFree(U642VOID(res.crtc_id_ptr));
	drmFree(U642VOID(res.connector_id_ptr));
	drmFree(U642VOID(res.encoder_id_ptr));

	return r;
}

drmModeFreeResources

void drmModeFreeResources(drmModeResPtr ptr)
{
	if (!ptr)
		return;

	drmFree(ptr->fbs);
	drmFree(ptr->crtcs);
	drmFree(ptr->connectors);
	drmFree(ptr->encoders);
	drmFree(ptr);
}

drmModeGetConnector

获取card的connector的所有信息

static drmModeConnectorPtr
_drmModeGetConnector(int fd, uint32_t connector_id, int probe)
{
	struct drm_mode_get_connector conn, counts;
	drmModeConnectorPtr r = NULL;
	struct drm_mode_modeinfo stack_mode;

	memclear(conn);
	conn.connector_id = connector_id;
	if (!probe) {
		conn.count_modes = 1;
		conn.modes_ptr = VOID2U64(&stack_mode);
	}

	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
		return 0;

retry:
	counts = conn;

	if (conn.count_props) {
		conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t)));
		if (!conn.props_ptr)
			goto err_allocs;
		conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t)));
		if (!conn.prop_values_ptr)
			goto err_allocs;
	}

	if (conn.count_modes) {
		conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo)));
		if (!conn.modes_ptr)
			goto err_allocs;
	} else {
		conn.count_modes = 1;
		conn.modes_ptr = VOID2U64(&stack_mode);
	}

	if (conn.count_encoders) {
		conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t)));
		if (!conn.encoders_ptr)
			goto err_allocs;
	}

	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
		goto err_allocs;

	/* The number of available connectors and etc may have changed with a
	 * hotplug event in between the ioctls, in which case the field is
	 * silently ignored by the kernel.
	 */
	if (counts.count_props < conn.count_props ||
	    counts.count_modes < conn.count_modes ||
	    counts.count_encoders < conn.count_encoders) {
		drmFree(U642VOID(conn.props_ptr));
		drmFree(U642VOID(conn.prop_values_ptr));
		if (U642VOID(conn.modes_ptr) != &stack_mode)
			drmFree(U642VOID(conn.modes_ptr));
		drmFree(U642VOID(conn.encoders_ptr));

		goto retry;
	}

	if(!(r = drmMalloc(sizeof(*r)))) {
		goto err_allocs;
	}

	r->connector_id = conn.connector_id;
	r->encoder_id = conn.encoder_id;
	r->connection   = conn.connection;
	r->mmWidth      = conn.mm_width;
	r->mmHeight     = conn.mm_height;
	/* convert subpixel from kernel to userspace */
	r->subpixel     = conn.subpixel + 1;
	r->count_modes  = conn.count_modes;
	r->count_props  = conn.count_props;
	r->props        = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t));
	r->prop_values  = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t));
	r->modes        = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo));
	r->count_encoders = conn.count_encoders;
	r->encoders     = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t));
	r->connector_type  = conn.connector_type;
	r->connector_type_id = conn.connector_type_id;

	if ((r->count_props && !r->props) ||
	    (r->count_props && !r->prop_values) ||
	    (r->count_modes && !r->modes) ||
	    (r->count_encoders && !r->encoders)) {
		drmFree(r->props);
		drmFree(r->prop_values);
		drmFree(r->modes);
		drmFree(r->encoders);
		drmFree(r);
		r = 0;
	}

err_allocs:
	drmFree(U642VOID(conn.prop_values_ptr));
	drmFree(U642VOID(conn.props_ptr));
	if (U642VOID(conn.modes_ptr) != &stack_mode)
		drmFree(U642VOID(conn.modes_ptr));
	drmFree(U642VOID(conn.encoders_ptr));

	return r;
}

drmModeFreeConnector

释放connector

void drmModeFreeConnector(drmModeConnectorPtr ptr)
{
	if (!ptr)
		return;

	drmFree(ptr->encoders);
	drmFree(ptr->prop_values);
	drmFree(ptr->props);
	drmFree(ptr->modes);
	drmFree(ptr);
}

drmModeObjectGetProperties

获取connector dpms (Display Power Manage System)属性

drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd,
						      uint32_t object_id,
						      uint32_t object_type)
{
	struct drm_mode_obj_get_properties properties;
	drmModeObjectPropertiesPtr ret = NULL;
	uint32_t count;

retry:
	memclear(properties);
	properties.obj_id = object_id;
	properties.obj_type = object_type;

	if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
		return 0;

	count = properties.count_props;

	if (count) {
		properties.props_ptr = VOID2U64(drmMalloc(count *
							  sizeof(uint32_t)));
		if (!properties.props_ptr)
			goto err_allocs;
		properties.prop_values_ptr = VOID2U64(drmMalloc(count *
						      sizeof(uint64_t)));
		if (!properties.prop_values_ptr)
			goto err_allocs;
	}

	if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
		goto err_allocs;

	if (count < properties.count_props) {
		drmFree(U642VOID(properties.props_ptr));
		drmFree(U642VOID(properties.prop_values_ptr));
		goto retry;
	}
	count = properties.count_props;

	ret = drmMalloc(sizeof(*ret));
	if (!ret)
		goto err_allocs;

	ret->count_props = count;
	ret->props = drmAllocCpy(U642VOID(properties.props_ptr),
				 count, sizeof(uint32_t));
	ret->prop_values = drmAllocCpy(U642VOID(properties.prop_values_ptr),
				       count, sizeof(uint64_t));
	if (ret->count_props && (!ret->props || !ret->prop_values)) {
		drmFree(ret->props);
		drmFree(ret->prop_values);
		drmFree(ret);
		ret = NULL;
	}

err_allocs:
	drmFree(U642VOID(properties.props_ptr));
	drmFree(U642VOID(properties.prop_values_ptr));
	return ret;
}

drmModeGetEncoder

获取Encoder

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

drmModeGetCrtc

Retrive information about the ctrt crtcId

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

drmModeAddFB

Creates a new framebuffer with an buffer object as its scanout buffer

创建一个具有buffer对象的framebuffer作为扫描buffer

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

drmModeRmFB

释放创建的framebuffer

int drmModeRmFB(int fd, uint32_t bufferId)
{
	return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
}

drmModeSetCrtc

Set the mode on a crtc crtcId with the given mode modeId.

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

例程

伪代码

1.open card

2.获取card的connector和encoder id

3.创建dumb buffer ,从内存中获取dumb 映射的偏移值,mmap申请,申请framebuffer 填充dumb buffer

4.销毁资源

代码

#include <stdio.h>
#include <errno.h>
#include "xf86drmMode.h"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>

#define DRM_CARD    "/dev/dri/card0"
#define check_ptr(ptr) do{ \
    if(ptr == NULL) { \
        printf("ptr is NULL\n"); \
        return -1; \
    } \
} while (0)


#define drm_print(fmt, args...) \
do \
{ \
	printf("func:%s line:%d "#fmt"\n",  __FUNCTION__, __LINE__, ##args); \
}while (0)

typedef struct _buffer_object {
	unsigned int width;
	unsigned int height;
	unsigned int pitch;
	unsigned int handle;
	unsigned int size;
	unsigned char *vaddr;
	unsigned int fb_id;
}buffer_object;


typedef struct  _drm_ctx{
    int fd;    
    buffer_object buf;
    unsigned int conector_id;
    unsigned int crtc_id;
    unsigned int encoder_id;
}drm_ctx;

drm_ctx gdrm_var;

static int creat_fb(int fd, buffer_object *bo)
{
    struct drm_mode_create_dumb creq;
    struct drm_mode_map_dumb mreq;
    int ret;

    creq.width = bo->width;
    creq.height = bo->height;
    creq.bpp = 32;

    ret = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
    if(ret != 0)
    {
        drm_print("ioctl creat dumb fail\n");
        return -1;
    }

    bo->pitch = creq.pitch;
    bo->handle = creq.handle;
    bo->size = creq.size;

    drmModeAddFB(fd, bo->width, bo->height, 24, 32, bo->pitch, bo->handle, &bo->fb_id);

    mreq.handle = bo->handle;
    ret = ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
    if(ret != 0)
    {
        drm_print("ioctl mmap dumb fail\n");
        return -1;
    }
        /* perform actual memory mapping */
    bo->vaddr = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
    check_ptr(bo->vaddr);
    //使用crtc驱动connector
    memset(bo->vaddr, 0xff, bo->size);

    return 0;
}

static int destroy_fb(int fd, buffer_object *bo)
{
    int ret;
    struct drm_mode_destroy_dumb dreq;

    drmModeRmFB(fd, bo->fb_id);
    dreq.handle = bo->handle;
    ret = ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
    if(ret != 0)
    {
        drm_print("ioctl destory dumb fail\n");
        return -1;
    }
    
    munmap(bo->vaddr, bo->size);
}

int main(int argc, char *argv[])
{
    //open card
    drmModeResPtr   resptr;
    drmModeConnectorPtr conptr;

    int ret;
    unsigned int fb;

    gdrm_var.fd = open(DRM_CARD, O_RDWR);
    if(gdrm_var.fd < 0)
    {
        perror("open card fail\n");
        return -1;
    }

    drm_print("fd%d\n", gdrm_var.fd);
    //获取card resource,include crtc connector encoder plane
    resptr = drmModeGetResources(gdrm_var.fd);
    check_ptr(resptr);

    gdrm_var.crtc_id = resptr->crtcs[0];
    gdrm_var.conector_id = resptr->connectors[0];
    drm_print("crtc id:%d conector_id %d", gdrm_var.crtc_id, gdrm_var.conector_id);
    //printf("%s %d crtc_id:%d con_id:%d\n", resptr->count_crtcs, resptr->count_connectors);
    //select which connector used
    conptr = drmModeGetConnector(gdrm_var.fd, gdrm_var.conector_id);
    check_ptr(conptr);
    gdrm_var.buf.width = conptr->modes[0].hdisplay;
    gdrm_var.buf.height = conptr->modes[0].vdisplay;
    drm_print("%d %d", gdrm_var.buf.width, gdrm_var.buf.height);
    //create framebuffer, fill dumb buffer
    creat_fb(gdrm_var.fd, &gdrm_var.buf);

    drmModeSetCrtc(gdrm_var.fd, gdrm_var.crtc_id, gdrm_var.buf.fb_id,
                   0, 0, &gdrm_var.conector_id, 1, &conptr->modes[0]);
    //destory dumb buffer
    sleep(5);
    destroy_fb(gdrm_var.fd, &gdrm_var.buf);
    drmModeFreeConnector(conptr);
    drmModeFreeResources(resptr);
    
    close(gdrm_var.fd);
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值