LIBDRM使用

一、备注

        文章中的DRM内容有一部分是下面链接的大佬整理的,还有一部分是其它来源整合,学习DRM的朋友一定要看看下面链接的文章,这个大佬写的很好

        参考链接:https://blog.csdn.net/hexiaolong2009/article/details/83720940

二、DRM框架简单介绍

        DRM 是linux 下的图形渲染架构(Direct Render Manager),是linux内核对显示框架进行分层设计的思想,相比于直接操作fb,drm框架提供更多的功能,包含图层合成、CMA、VSYNC等,而且架构更方便驱动人员维护和使用

        framebuffer:帧缓存,帧缓存并不是指的显存上的某一块区域,而是DRM抽象出来的一个概念,用fb_id表示

        plane:图层,有的硬件支持多层合成显示,Plane是连接FB与CRTC的纽带,是内存的搬运工

        crtc:阴级摄像管上下文,将显存图像数据转换成硬件时序信号传输到encoder(crtc和plane是一个硬件模块?)

        encoder:encoder后面接connector,比如说hdmi、mipi(connector我理解为hdmi、mipi等接口和线的抽象形式)等,但它们的时序、协议不同,所以就需要encoder(例如hdmi发送器)将crtc传输过来的信号转换成hdmi、mipi支持的协议再通过connector传输到显示器

        connector:connector我理解为hdmi、mipi等接口和线的抽象形式

        整个流程我理解为:

        framebuffer(显存中的图像数据) -> plane(图层合并、缩放等处理)-> ctrc(将显示数据并转换成encoder可以接受的硬件信号)-> encoder(显示数据转换成不同显示输出接口的硬件信号)-> connector

扫描二维码关注公众号,回复: 14603237 查看本文章

三、libdrm介绍

        libdrm的作用就是将内核功能封装成 一系列的open/close/ioctl 等标准接口,应用程序调用这些接口来驱动设备实现画面显示,绝大部分可以分成两类行为:Graphics Execution Manager (GEM)、Kernel Mode-Setting (KMS),gem:显存管理,如显存的分配和释放,kms:显示模式管理,如分辨率等的设置

        a69ff083341748e22bdb9a4bc081e863.png         

四、libdrm安装

        libdrm下载链接:https://dri.freedesktop.org/libdrm/

        tar -zxvf libdrm-2.4.89.tar.gz && cd libdrm-2.4.89 && mkdir install    

         执行./configure -h,看一下需要加入那些配置参数,例如下图红框位置的库安装位置(--prefix,例如当前目录的install),你在什么平台上面使用(--host,例如aarch64-linux-gnu)

efbecc24bca445990c26ad47f3edc2a7.pngfd25c1db30e26fbe300dc9b23677b235.png

        执行mkdir install && ./configure --prefix=/.../install/ --host=aarch64-linux-gnu && make && make install,结果如下        df8678f10d04637618c5add5b2296afd.png

五、基于libdrm的简单程序编写(输出红绿蓝)

#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include "xf86drm.h"
#include "xf86drmMode.h"

#define uint32_t unsigned int 

struct framebuffer{
	uint32_t size;
	uint32_t handle;	
	uint32_t fb_id;
	uint32_t *vaddr;	
};

static void create_fb(int fd,uint32_t width, uint32_t height, uint32_t color ,struct framebuffer *buf)
{
	struct drm_mode_create_dumb create = {};
 	struct drm_mode_map_dumb map = {};
	uint32_t i;
	uint32_t fb_id;

	create.width = width;
	create.height = height;
	create.bpp = 32;
	drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);	//创建显存,返回一个handle

	drmModeAddFB(fd, create.width, create.height, 24, 32, create.pitch,create.handle, &fb_id); 
	
	map.handle = create.handle;
	drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);	//显存绑定fd,并根据handle返回offset

	//通过offset找到对应的显存(framebuffer)并映射到用户空间
	uint32_t *vaddr = mmap(0, create.size, PROT_READ | PROT_WRITE,MAP_SHARED, fd, map.offset);	

	for (i = 0; i < (create.size / 4); i++)
		vaddr[i] = color;

	buf->vaddr=vaddr;
	buf->handle=create.handle;
	buf->size=create.size;
	buf->fb_id=fb_id;

	return;
}

static void release_fb(int fd, struct framebuffer *buf)
{
	struct drm_mode_destroy_dumb destroy = {};
	destroy.handle = buf->handle;

	drmModeRmFB(fd, buf->fb_id);
	munmap(buf->vaddr, buf->size);
	drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
}

int main(int argc, char **argv)
{
	int fd;
	struct framebuffer buf[3];
	drmModeConnector *connector;
	drmModeRes *resources;
	uint32_t conn_id;
	uint32_t crtc_id;


	fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);	//打开card0,card0一般绑定HDMI和LVDS

	resources = drmModeGetResources(fd);	//获取drmModeRes资源,包含fb、crtc、encoder、connector等
	
	crtc_id = resources->crtcs[0];			//获取crtc id
	conn_id = resources->connectors[0];		//获取connector id

	connector = drmModeGetConnector(fd, conn_id);	//根据connector_id获取connector资源

	printf("hdisplay:%d vdisplay:%d\n",connector->modes[0].hdisplay,connector->modes[0].vdisplay);

	create_fb(fd,connector->modes[0].hdisplay,connector->modes[0].vdisplay, 0xff0000, &buf[0]);	//创建显存和上色
	create_fb(fd,connector->modes[0].hdisplay,connector->modes[0].vdisplay, 0x00ff00, &buf[1]);	
	create_fb(fd,connector->modes[0].hdisplay,connector->modes[0].vdisplay, 0x0000ff, &buf[2]);	

	drmModeSetCrtc(fd, crtc_id, buf[0].fb_id,	
			0, 0, &conn_id, 1, &connector->modes[0]);	//初始化和设置crtc,对应显存立即刷新
	sleep(5);

	drmModeSetCrtc(fd, crtc_id, buf[1].fb_id,
		0, 0, &conn_id, 1, &connector->modes[0]);
	sleep(5);

	drmModeSetCrtc(fd, crtc_id, buf[2].fb_id,
		0, 0, &conn_id, 1, &connector->modes[0]);
	sleep(5);

	release_fb(fd, &buf[0]);
	release_fb(fd, &buf[1]);
	release_fb(fd, &buf[2]);

	drmModeFreeConnector(connector);
	drmModeFreeResources(resources);

	close(fd);

	return 0;
}

六、测试

        执行./drm_test,效果如下

        

猜你喜欢

转载自blog.csdn.net/QQ135102692/article/details/125031907