Drm 例程2 双buffer 显示
显示过程中,drm是通过申请framebuffer 填充其中的dumb的buf来显示的,drmModeAddFB对不同的dumb buff拿到的bufid也不一样,
最终使用drmModeSetCrtc来设定参数,使用dumb的bufid来填充相应的buf值
代码
#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 Chartreuse 0x7FFF00
#define Yellow 0xFFFF00
#define GoldEnrod 0xDAA520
#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 int *vaddr;
unsigned int fb_id;
}buffer_object;
typedef struct _drm_ctx{
int fd;
buffer_object buf[2];
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, uint32_t color)
{
struct drm_mode_create_dumb creq;
struct drm_mode_map_dumb mreq;
int ret;
uint32_t i;
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;
drm_print("bo pitch:%d", bo->pitch);
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, 0xB4, bo->size);
drm_print("bo size:%d", bo->size);//按照官方doc size=(height * pitch + width) * bpp / 4 跟实际打印出来的值 height * width *4 不大一样
for (i = 0; i < (bo->size/4); i++)
bo->vaddr[i] = color;
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[0].width = conptr->modes[0].hdisplay;
gdrm_var.buf[0].height = conptr->modes[0].vdisplay;
gdrm_var.buf[1].width = conptr->modes[0].hdisplay;
gdrm_var.buf[1].height = conptr->modes[0].vdisplay;
drm_print("%d %d %d", gdrm_var.buf[0].width, gdrm_var.buf[0].height, gdrm_var.buf[0].size);
//create framebuffer, fill dumb buffer
creat_fb(gdrm_var.fd, &gdrm_var.buf[0], Chartreuse);
creat_fb(gdrm_var.fd, &gdrm_var.buf[1], GoldEnrod);
drmModeSetCrtc(gdrm_var.fd, gdrm_var.crtc_id, gdrm_var.buf[0].fb_id,
0, 0, &gdrm_var.conector_id, 1, &conptr->modes[0]);
sleep(2);
drmModeSetCrtc(gdrm_var.fd, gdrm_var.crtc_id, gdrm_var.buf[1].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[0]);
destroy_fb(gdrm_var.fd, &gdrm_var.buf[1]);
drmModeFreeConnector(conptr);
drmModeFreeResources(resptr);
close(gdrm_var.fd);
}