刚开始学习,记忆不是很好,容易忘,边学边记,阅读的速度会比较慢,看的会比较仔细。

这边对该示例进行简单的修改,从多次遍历改用固定一个,实验效果与前面相同。相对来说也是进行了一定的简化,看起来应该会更容易理解一些。
若想具体查看相关函数和结构体的样子可看下篇:学习篇5:相关函数与结构体
详细请看:
  David Herrmann’s Blog: Linux DRM Mode-Setting API
  David Herrmann’s Github: drm-howto/modeset.c


简化代码

#define _GNU_SOURCE

#include <fcntl.h>		//open所需
#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>


typedef struct modeset_dev {
	uint32_t width;			//缓冲区对象的宽度
	uint32_t height;			//缓冲区对象的高度
	uint32_t stride;			//缓冲区对象的stride值
	uint32_t size;				//内存映射缓冲区的大小
	uint32_t handle;			//可以绘制的缓冲区对象的DRM句柄
	uint8_t *map;				//指向内存映射缓冲区的指针
	drmModeModeInfo mode;			//想使用的显示模式
	uint32_t fb;				//一个缓冲对象作为扫描缓冲区的framebuffer句柄
	uint32_t conn;				//想在这个缓冲区中使用的连接器ID
	uint32_t crtc;				//想在这个连接器中使用的crtc ID
	drmModeCrtc *saved_crtc;		//更改crtc之前的配置。我们使用它这样我们可以在退出时恢复相同的模式。
}modeset_dev;



static int modeset_create_fb(int fd, struct modeset_dev *dev)
{
	struct drm_mode_create_dumb creq;		//创建dumb的结构体,包含宽/高/像素位/间距等
	struct drm_mode_map_dumb mreq;		//handle用来映射
	
	memset(&creq, 0, sizeof(creq));		//结构体初始化
	creq.width = dev->width;			//创建设备宽度大小的dumb
	creq.height = dev->height;			//创建设备高度大小的dumb
	creq.bpp = 32;					//创建每个像素32位
	drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);	//发出DRM输入/输出控制(就看作创建dumb?)

	dev->stride = creq.pitch;			//根据查看drm_mode.h中可知这边三个结构体变量是用来返回的
	dev->size = creq.size;
	dev->handle = creq.handle;

	drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride,dev->handle, &dev->fb);	//创建指定大小的framebuffer

	memset(&mreq, 0, sizeof(mreq));		//结构体初始化
	mreq.handle = dev->handle;			//进行映射
	drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);	//发出DRM输入/输出控制(就看作映射dumb?)
	
	dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED,fd, mreq.offset);		//内存映射的缓冲区
	
	memset(dev->map, 0, dev->size);		//对framebuffer清空0

	return 0;
}
/*	
	所有资源———————》连接器信息———————》编码器信息———————》CRTC信息

*/
static  modeset_dev* modeset_prepare(int fd)
{
	drmModeRes *res;			//资源的结构体指针。包含CRTC,编码器,连接器的信息
	drmModeConnector *conn;		//连接器的结构体指针。包含连接器ID和模式等。
	drmModeEncoder *enc;			//编码器的结构体指针。包含编码器ID等。
	static struct modeset_dev *dev;		
	
	res = drmModeGetResources(fd);			//返回指针,即:资源结构体的首地址。
	conn = drmModeGetConnector(fd, res->connectors[0]);	//返回指针,即:连接器结构体的首地址。
	
	dev = malloc(sizeof(*dev));				//创建一块空间,用来存储当前设备的相关信息
	memset(dev, 0, sizeof(*dev));				//对该空间进行初始化
	dev->conn = conn->connector_id;			//从连接器结构体中得到ID传入设备信息结构体中,即:dev->conn的值


	memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode));//将连接器结构中模式传入设备信息结构体中,即:dev->mode
	dev->width = conn->modes[0].hdisplay;			 //从连接器模式中获取到宽度传入设备信息结构体中,即:dev->width
	dev->height = conn->modes[0].vdisplay;		 //从连接器模式中获取到高度传入设备信息结构体中,即:dev->height


	enc = drmModeGetEncoder(fd, conn->encoder_id);	//返回指针,即:编码器结构体的首地址
	dev->crtc = enc->crtc_id;				//从编码器结构体中得到CRTC的ID传入设备信息结构体,即:dev->crtc

	
	modeset_create_fb(fd, dev);				//创建一个合适的框架缓冲区

	//dev->saved_crtc = drmModeGetCrtc(fd, dev->crtc);
	drmModeSetCrtc(fd, dev->crtc, dev->fb, 0, 0, &dev->conn, 1, &dev->mode);	//设置CRTC配置,有crtc的ID,fb的ID,连接器的ID,设备(连接器)模式

	drmModeFreeEncoder(enc);
	drmModeFreeConnector(conn);
	drmModeFreeResources(res);
	return dev;
}





static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod)
{
	uint8_t next;

	next = cur + (*up ? 1 : -1) * (rand() % mod);
	if ((*up && next < cur) || (!*up && next > cur)) {
		*up = !*up;
		next = cur;
	}

	return next;
}
/*modeset_draw():在所有已配置的framebuffer中绘制纯色*/
static void modeset_draw(modeset_dev *dev)
{
	uint8_t r, g, b;
	bool r_up, g_up, b_up;
	unsigned int i, j, k, off;
	
	srand(time(NULL));
	r = rand() % 0xff;
	g = rand() % 0xff;
	b = rand() % 0xff;
	r_up = g_up = b_up = true;
	
	for (i = 0; i < 50; ++i) {
		r = next_color(&r_up, r, 20);
		g = next_color(&g_up, g, 10);
		b = next_color(&b_up, b, 5);
			for (j = 0; j < dev->height; ++j) {
				for (k = 0; k < dev->width; ++k) {
					off = dev->stride * j + k * 4;
					*(uint32_t*)&dev->map[off] = (r << 16) | (g << 8) | b;
				}
			}
		usleep(100000);
	}
}



static void modeset_cleanup(int fd,modeset_dev *dev)
{
	struct drm_mode_destroy_dumb dreq;
	
	drmModeSetCrtc(fd, dev->saved_crtc->crtc_id,dev->saved_crtc->buffer_id,dev->saved_crtc->x,dev->saved_crtc->y, &dev->conn,1,&dev->saved_crtc->mode);//恢复保存的CRTC配置
	drmModeFreeCrtc(dev->saved_crtc);
	munmap(dev->map, dev->size);				//unmap buffe		
	drmModeRmFB(fd, dev->fb);				//删除framebuffer	
	memset(&dreq, 0, sizeof(dreq));			//删除dumb buffer
	dreq.handle = dev->handle;
	drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);		
	free(dev);						//删除dumb buffer		
}
  int main(int argc, char **argv)
{
	int fd;
	struct modeset_dev *dev;
	fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);			//打开设备

	dev = modeset_prepare(fd);						//设备的相关准备(crtc,编码器,连接器,fb),返回指针,指向设备信息
	
	modeset_draw(dev);							//绘制
	
	modeset_cleanup(fd,dev);						//清空所有

}