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