刚开始学习,记忆不是很好,容易忘,边学边记,阅读的速度会比较慢,看的会比较仔细。
这边对该示例进行简单的修改,从多次遍历改用固定一个,实验效果与前面相同。相对来说也是进行了一定的简化,看起来应该会更容易理解一些。
若想具体查看相关函数和结构体的样子可看下篇:学习篇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); //清空所有
}
评论(0)
您还未登录,请登录后发表或查看评论