Linux驱动:framebuffer应用层实践
查看驱动是否存在
/sys/class/graphics 路径解析
为什么 framebuffer 驱动使用这个路径?
Linux 设备模型设计:
Linux 采用分层设备模型,将设备按功能分类到不同的 “类” 中
/sys/class/目录下存放所有设备类,每个子目录代表一种设备类型
图形显示设备被归类到graphics类中
Framebuffer 的特殊地位:
Framebuffer 是 Linux 中最基本的图形显示抽象层
它提供了统一的接口,允许应用程序直接访问显示内存
所有图形驱动(包括控制台、X Window 系统等)都依赖于 framebuffer
驱动注册机制:
当 framebuffer 驱动初始化时,会通过register_framebuffer()函数注册设备
该函数会自动在/sys/class/graphics下创建对应的设备节点(如fb0)
代码查看信息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>int main(int argc, char *argv[]) {int fd;struct fb_var_screeninfo vinfo;struct fb_fix_screeninfo finfo;char *fbdev = "/dev/fb0";// Use specified device if provided as command-line argumentif (argc > 1) {fbdev = argv[1];}// Open framebuffer devicefd = open(fbdev, O_RDONLY);if (fd == -1) {perror("Failed to open framebuffer device");return EXIT_FAILURE;}// Get variable screen informationif (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) {perror("Failed to get variable screen information");close(fd);return EXIT_FAILURE;}// Get fixed screen informationif (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) {perror("Failed to get fixed screen information");close(fd);return EXIT_FAILURE;}// Print device informationprintf("Framebuffer Device: %s\n", fbdev);printf("Device ID: %s\n", finfo.id);printf("Virtual Resolution: %dx%d\n", vinfo.xres_virtual, vinfo.yres_virtual);printf("Visible Resolution: %dx%d\n", vinfo.xres, vinfo.yres);printf("Bits per Pixel: %d\n", vinfo.bits_per_pixel);printf("Memory Size: %.2f MB\n", finfo.smem_len / (1024.0 * 1024.0));// Print color formatprintf("Color Format:\n");printf(" Red: %d bits, Offset: %d\n", vinfo.red.length, vinfo.red.offset);printf(" Green: %d bits, Offset: %d\n", vinfo.green.length, vinfo.green.offset);printf(" Blue: %d bits, Offset: %d\n", vinfo.blue.length, vinfo.blue.offset);printf(" Alpha: %d bits, Offset: %d\n", vinfo.transp.length, vinfo.transp.offset);// Print screen refresh rateif (vinfo.pixclock > 0) {float hz = 1000000000.0 / vinfo.pixclock;printf("Pixel Clock: %.2f MHz\n", hz / 1000.0);printf("Approximate Refresh Rate: %.2f Hz\n", hz / (vinfo.xres * vinfo.yres));}close(fd);return EXIT_SUCCESS;
}
struct fb_var_screeninfo {__u32 xres; // 可见水平分辨率(像素)__u32 yres; // 可见垂直分辨率(像素)__u32 xres_virtual; // 虚拟水平分辨率(像素)__u32 yres_virtual; // 虚拟垂直分辨率(像素)__u32 xoffset; // 当前水平偏移(像素)__u32 yoffset; // 当前垂直偏移(像素)__u32 bits_per_pixel; // 每个像素的位数(像素深度)// 颜色位域定义struct fb_bitfield red; // 红色位域struct fb_bitfield green; // 绿色位域struct fb_bitfield blue; // 蓝色位域struct fb_bitfield transp; // 透明度位域// 显示时序参数__u32 pixclock; // 像素时钟(皮秒)__u32 left_margin; // 左边距(像素)__u32 right_margin; // 右边距(像素)__u32 upper_margin; // 上边距(像素)__u32 lower_margin; // 下边距(像素)__u32 hsync_len; // 水平同步长度(像素)__u32 vsync_len; // 垂直同步长度(像素)// 显示方式__u32 sync; // 同步类型__u32 vmode; // 显示模式__u32 rotate; // 旋转角度// 保留字段__u32 reserved[5];
};
struct fb_fix_screeninfo {char id[16]; // 驱动标识字符串unsigned long smem_start; // 帧缓冲内存的物理起始地址__u32 smem_len; // 帧缓冲内存的长度(字节)__u32 type; // 硬件类型__u32 type_aux; // 硬件类型辅助信息__u32 visual; // 视觉类型(如真彩色、伪彩色等)__u16 xpanstep; // 如果支持水平平移,单位是像素__u16 ypanstep; // 如果支持垂直平移,单位是像素__u16 ywrapstep; // 如果支持垂直回绕,单位是像素__u32 line_length; // 一行的字节数unsigned long mmio_start; // 内存映射I/O的物理起始地址__u32 mmio_len; // 内存映射I/O的长度__u32 accel; // 加速类型__u16 reserved[3]; // 保留字段
};
双缓存(Double Buffering)的原理与应用解析
双缓存的基本概念
双缓存是计算机图形学和显示系统中一种重要的技术机制,其核心思想是通过维护两个缓冲区(Buffer) 来解决图像显示过程中的闪烁、撕裂和渲染效率问题。在传统单缓存模式下,图像的绘制和显示在同一个内存区域完成,会导致明显的视觉缺陷;而双缓存通过分离 “绘制” 和 “显示” 的内存空间,实现更流畅的图形输出。
双缓存在 Linux Framebuffer 中的实现
在 Linux 系统的帧缓冲(Framebuffer)机制中,双缓存通过以下方式实现:
驱动层支持
显卡驱动(如 Intel、Nvidia、ARM Mali)通过fb_var_screeninfo结构体的yres_virtual参数支持虚拟分辨率,为双缓存提供内存空间。
例如,当物理分辨率为 1920×1080 时,虚拟分辨率可设为 1920×2160,后 1080 行作为后缓冲区。
应用层接口
mmap()映射帧缓冲内存和虚拟分辨率大小一致。
通过mmap()映射帧缓冲内存后,应用程序可手动管理前后缓冲区(如 Qt 的QOffscreenSurface)。
部分图形库(如 SDL2、OpenGL)会自动封装双缓存逻辑,调用SDL_GL_SwapBuffers()等函数即可触发交换。
刷背景
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdint.h>// 颜色结构体,支持不同像素格式
typedef union {uint8_t rgba[4]; // RGBA格式(8位/通道)uint16_t rgb565; // RGB565格式(16位)uint32_t rgb888; // RGB888格式(24位)uint32_t argb8888; // ARGB8888格式(32位)
} color_t;// 显示设备信息结构体
typedef struct {int fd; // 设备文件描述符struct fb_var_screeninfo vinfo; // 可变屏幕信息struct fb_fix_screeninfo finfo; // 固定屏幕信息char *device_path; // 设备路径long int screen_size; // 屏幕内存大小char *fbp; // 映射的内存地址
} fb_device_t;// 设置颜色值(支持RGBA格式)
void set_color(color_t *color, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {color->rgba[0] = r;color->rgba[1] = g;color->rgba[2] = b;color->rgba[3] = a;
}// 初始化framebuffer设备
int init_fb_device(fb_device_t *fb, const char *device_path) {// 打开设备fb->fd = open(device_path, O_RDWR);if (fb->fd == -1) {perror("无法打开framebuffer设备");return -1;}// 获取屏幕信息if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vinfo) == -1) {perror("无法获取可变屏幕信息");close(fb->fd);return -1;}if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->finfo) == -1) {perror("无法获取固定屏幕信息");close(fb->fd);return -1;}// 计算屏幕大小fb->screen_size = fb->vinfo.xres * fb->vinfo.yres * fb->vinfo.bits_per_pixel / 8;fb->device_path = strdup(device_path);return 0;
}// 映射framebuffer内存
int map_fb_memory(fb_device_t *fb) {fb->fbp = (char *)mmap(0, fb->screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, 0);if ((intptr_t)fb->fbp == -1) {perror("无法映射framebuffer设备");return -1;}return 0;
}int fill_background(fb_device_t *fb, color_t color) {long int location = 0;int pixel_size = fb->vinfo.bits_per_pixel / 8;int y, x; // 将变量声明移到循环外部printf("填充分辨率: %dx%d, 像素深度: %d位\n", fb->vinfo.xres, fb->vinfo.yres, fb->vinfo.bits_per_pixel);for (y = 0; y < fb->vinfo.yres; y++) {for (x = 0; x < fb->vinfo.xres; x++) {location = (x + fb->vinfo.xoffset) * pixel_size +(y + fb->vinfo.yoffset) * fb->finfo.line_length;switch (fb->vinfo.bits_per_pixel) {case 8:// 8位色:简化为灰度或调色板索引*(fb->fbp + location) = (color.rgba[0] >> 5) << 5 | (color.rgba[1] >> 6) << 2 | (color.rgba[2] >> 5);break;case 16:// RGB565格式color.rgb565 = ((color.rgba[0] >> 3) << 11) | ((color.rgba[1] >> 2) << 5) | (color.rgba[2] >> 3);*((uint16_t *)(fb->fbp + location)) = color.rgb565;break;case 24:// RGB888格式color.rgb888 = (color.rgba[0] << 16) | (color.rgba[1] << 8) | color.rgba[2];*((uint32_t *)(fb->fbp + location)) = color.rgb888;break;case 32:// ARGB8888格式color.argb8888 = (color.rgba[3] << 24) | (color.rgba[0] << 16) | (color.rgba[1] << 8) | color.rgba[2];*((uint32_t *)(fb->fbp + location)) = color.argb8888;break;default:printf("不支持的像素深度: %d\n", fb->vinfo.bits_per_pixel);return -1;}}}return 0;
}// 释放framebuffer资源
void cleanup_fb_device(fb_device_t *fb) {if (fb->fbp) {munmap(fb->fbp, fb->screen_size);fb->fbp = NULL;}if (fb->fd > 0) {close(fb->fd);fb->fd = 0;}if (fb->device_path) {free(fb->device_path);fb->device_path = NULL;}
}int main(int argc, char *argv[]) {fb_device_t fb = {0};color_t bg_color = {0};uint8_t r = 0, g = 0, b = 0; // 默认黑色背景//uint8_t r = 0xFF, g =0xFF, b = 0xFF; // 白色背景// 解析命令行参数const char *device_path = "/dev/fb0";if (argc > 1) {device_path = argv[1];}if (argc > 4) {r = atoi(argv[2]);g = atoi(argv[3]);b = atoi(argv[4]);}// 初始化设备if (init_fb_device(&fb, device_path) < 0) {return EXIT_FAILURE;}// 打印设备信息printf("Framebuffer设备: %s\n", fb.device_path);printf("分辨率: %dx%d, 像素深度: %d位\n", fb.vinfo.xres, fb.vinfo.yres, fb.vinfo.bits_per_pixel);// 设置颜色set_color(&bg_color, r, g, b, 255);printf("填充颜色: RGB(%d, %d, %d)\n", r, g, b);// 映射内存if (map_fb_memory(&fb) < 0) {cleanup_fb_device(&fb);return EXIT_FAILURE;}printf("成功映射内存,开始填充背景色...\n");// 填充背景色if (fill_background(&fb, bg_color) < 0) {cleanup_fb_device(&fb);return EXIT_FAILURE;}printf("背景色填充完成!\n");printf("提示: 按Ctrl+C退出程序,颜色将保留在屏幕上。\n");sleep(3); // 等待3秒以便查看效果// 释放资源cleanup_fb_device(&fb);return EXIT_SUCCESS;
}
各种图型的绘制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdint.h>
#include <math.h>// 颜色结构体,支持不同像素格式
typedef union {uint8_t rgba[4]; // RGBA格式(8位/通道)uint16_t rgb565; // RGB565格式(16位)uint32_t rgb888; // RGB888格式(24位)uint32_t argb8888; // ARGB8888格式(32位)
} color_t;// 显示设备信息结构体
typedef struct {int fd; // 设备文件描述符struct fb_var_screeninfo vinfo; // 可变屏幕信息struct fb_fix_screeninfo finfo; // 固定屏幕信息char *device_path; // 设备路径long int screen_size; // 屏幕内存大小char *fbp; // 映射的内存地址
} fb_device_t;// 设置颜色值(支持RGBA格式)
void set_color(color_t *color, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {color->rgba[0] = r;color->rgba[1] = g;color->rgba[2] = b;color->rgba[3] = a;
}// 初始化framebuffer设备
int init_fb_device(fb_device_t *fb, const char *device_path) {// 打开设备fb->fd = open(device_path, O_RDWR);if (fb->fd == -1) {perror("无法打开framebuffer设备");return -1;}// 获取屏幕信息if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vinfo) == -1) {perror("无法获取可变屏幕信息");close(fb->fd);return -1;}if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->finfo) == -1) {perror("无法获取固定屏幕信息");close(fb->fd);return -1;}// 计算屏幕大小fb->screen_size = fb->vinfo.xres * fb->vinfo.yres * fb->vinfo.bits_per_pixel / 8;fb->device_path = strdup(device_path);return 0;
}// 映射framebuffer内存
int map_fb_memory(fb_device_t *fb) {fb->fbp = (char *)mmap(0, fb->screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, 0);if ((intptr_t)fb->fbp == -1) {perror("无法映射framebuffer设备");return -1;}return 0;
}// 填充背景色
int fill_background(fb_device_t *fb, color_t color) {long int location = 0;int pixel_size = fb->vinfo.bits_per_pixel / 8;int y, x; // 在函数开头声明变量for (y = 0; y < fb->vinfo.yres; y++) {for (x = 0; x < fb->vinfo.xres; x++) {location = (x + fb->vinfo.xoffset) * pixel_size +(y + fb->vinfo.yoffset) * fb->finfo.line_length;switch (fb->vinfo.bits_per_pixel) {case 8:*(fb->fbp + location) = (color.rgba[0] >> 5) << 5 | (color.rgba[1] >> 6) << 2 | (color.rgba[2] >> 5);break;case 16:color.rgb565 = ((color.rgba[0] >> 3) << 11) | ((color.rgba[1] >> 2) << 5) | (color.rgba[2] >> 3);*((uint16_t *)(fb->fbp + location)) = color.rgb565;break;case 24:color.rgb888 = (color.rgba[0] << 16) | (color.rgba[1] << 8) | color.rgba[2];*((uint32_t *)(fb->fbp + location)) = color.rgb888;break;case 32:color.argb8888 = (color.rgba[3] << 24) | (color.rgba[0] << 16) | (color.rgba[1] << 8) | color.rgba[2];*((uint32_t *)(fb->fbp + location)) = color.argb8888;break;default:printf("不支持的像素深度: %d\n", fb->vinfo.bits_per_pixel);return -1;}}}return 0;
}// 绘制单个像素
void draw_pixel(fb_device_t *fb, int x, int y, color_t color) {if (x < 0 || x >= fb->vinfo.xres || y < 0 || y >= fb->vinfo.yres)return;long int location = (x + fb->vinfo.xoffset) * (fb->vinfo.bits_per_pixel / 8) +(y + fb->vinfo.yoffset) * fb->finfo.line_length;switch (fb->vinfo.bits_per_pixel) {case 8:*(fb->fbp + location) = (color.rgba[0] >> 5) << 5 | (color.rgba[1] >> 6) << 2 | (color.rgba[2] >> 5);break;case 16:color.rgb565 = ((color.rgba[0] >> 3) << 11) | ((color.rgba[1] >> 2) << 5) | (color.rgba[2] >> 3);*((uint16_t *)(fb->fbp + location)) = color.rgb565;break;case 24:color.rgb888 = (color.rgba[0] << 16) | (color.rgba[1] << 8) | color.rgba[2];*((uint32_t *)(fb->fbp + location)) = color.rgb888;break;case 32:color.argb8888 = (color.rgba[3] << 24) | (color.rgba[0] << 16) | (color.rgba[1] << 8) | color.rgba[2];*((uint32_t *)(fb->fbp + location)) = color.argb8888;break;}
}// Bresenham直线算法 - 绘制横线
void draw_hline(fb_device_t *fb, int x1, int x2, int y, color_t color) {int temp, x; // 在函数开头声明变量if (x1 > x2) { temp = x1; x1 = x2; x2 = temp; }for (x = x1; x <= x2; x++) {draw_pixel(fb, x, y, color);}
}// Bresenham直线算法 - 绘制竖线
void draw_vline(fb_device_t *fb, int x, int y1, int y2, color_t color) {int temp, y; // 在函数开头声明变量if (y1 > y2) { temp = y1; y1 = y2; y2 = temp; }for (y = y1; y <= y2; y++) {draw_pixel(fb, x, y, color);}
}// Bresenham直线算法 - 绘制任意直线
void draw_line(fb_device_t *fb, int x1, int y1, int x2, int y2, color_t color) {int dx = abs(x2 - x1);int dy = abs(y2 - y1);int sx = x1 < x2 ? 1 : -1;int sy = y1 < y2 ? 1 : -1;int err = dx - dy;int x = x1, y = y1; // 在函数开头声明变量while (1) {draw_pixel(fb, x, y, color);if (x == x2 && y == y2) break;int e2 = 2 * err;if (e2 > -dy) { err -= dy; x += sx; }if (e2 < dx) { err += dx; y += sy; }}
}// Bresenham圆算法 - 绘制圆形
void draw_circle(fb_device_t *fb, int x0, int y0, int r, color_t color) {int x = r, y = 0; // 在函数开头声明变量int dx = 1, dy = 1;int err = x - dy;while (x >= y) {draw_pixel(fb, x0 + x, y0 + y, color);draw_pixel(fb, x0 + y, y0 + x, color);draw_pixel(fb, x0 - y, y0 + x, color);draw_pixel(fb, x0 - x, y0 + y, color);draw_pixel(fb, x0 - x, y0 - y, color);draw_pixel(fb, x0 - y, y0 - x, color);draw_pixel(fb, x0 + y, y0 - x, color);draw_pixel(fb, x0 + x, y0 - y, color);if (err <= 0) {y++;err += dy;dy += 2;}if (err > 0) {x--;dx += 2;err += dx - dy;}}
}// 绘制三角形 (使用扫描线算法填充)
void draw_triangle(fb_device_t *fb, int x1, int y1, int x2, int y2, int x3, int y3, color_t color) {int temp, y_mid, x_mid; // 在函数开头声明变量int y_sorted[3] = {y1, y2, y3};int x_sorted[3] = {x1, x2, x3};int i, j; // 在函数开头声明变量// 按y坐标排序顶点(简化版,实际应保持x和y的对应关系)for (i = 0; i < 3; i++) {for (j = i + 1; j < 3; j++) {if (y_sorted[i] > y_sorted[j]) {temp = y_sorted[i]; y_sorted[i] = y_sorted[j]; y_sorted[j] = temp;temp = x_sorted[i]; x_sorted[i] = x_sorted[j]; x_sorted[j] = temp;}}}y1 = y_sorted[0]; x1 = x_sorted[0];y2 = y_sorted[1]; x2 = x_sorted[1];y3 = y_sorted[2]; x3 = x_sorted[2];// 绘制三角形的三条边draw_line(fb, x1, y1, x2, y2, color);draw_line(fb, x2, y2, x3, y3, color);draw_line(fb, x3, y3, x1, y1, color);// 扫描线填充if (y2 == y3) {// 平底三角形int y, x_left, x_right; // 在需要时声明变量(也可在函数开头声明)for (y = y1; y <= y2; y++) {x_left = x1 + (y - y1) * (x2 - x1) / (y2 - y1);x_right = x1 + (y - y1) * (x3 - x1) / (y3 - y1);draw_hline(fb, x_left, x_right, y, color);}} else if (y1 == y2) {// 平顶三角形int y, x_left, x_right;for (y = y2; y <= y3; y++) {x_left = x2 + (y - y2) * (x3 - x2) / (y3 - y2);x_right = x1 + (y - y1) * (x3 - x1) / (y3 - y1);draw_hline(fb, x_left, x_right, y, color);}} else {// 一般三角形,分为上下两部分y_mid = y2;x_mid = x1 + (y_mid - y1) * (x3 - x1) / (y3 - y1);// 上半部分 - 平底三角形int y, x_left, x_right;for (y = y1; y <= y_mid; y++) {x_left = x1 + (y - y1) * (x2 - x1) / (y2 - y1);x_right = x1 + (y - y1) * (x_mid - x1) / (y_mid - y1);draw_hline(fb, x_left, x_right, y, color);}// 下半部分 - 平顶三角形int y2d, x_left2, x_right2; // 改用不同变量名避免冲突for (y2d = y_mid; y2d <= y3; y2d++) {x_left2 = x2 + (y2d - y2) * (x3 - x2) / (y3 - y2);x_right2 = x1 + (y2d - y1) * (x3 - x1) / (y3 - y1);draw_hline(fb, x_left2, x_right2, y2d, color);}}
}// 绘制正方形
void draw_square(fb_device_t *fb, int x, int y, int size, color_t color) {draw_hline(fb, x, x + size - 1, y, color);draw_hline(fb, x, x + size - 1, y + size - 1, color);draw_vline(fb, x, y, y + size - 1, color);draw_vline(fb, x + size - 1, y, y + size - 1, color);
}// 绘制五角星
void draw_star(fb_device_t *fb, int x0, int y0, int outer_r, int inner_r, color_t color) {const double PI = 3.14159265358979323846;int points[10]; // 五角星有10个顶点int i; // 在函数开头声明变量double angle, x, y;// 计算五角星顶点坐标for (i = 0; i < 10; i++) {angle = i * 2 * PI / 10 + PI / 2; // 从顶部开始double r = (i % 2 == 0) ? outer_r : inner_r;x = x0 + (r * cos(angle));y = y0 + (r * sin(angle));points[i * 2] = (int)x;points[i * 2 + 1] = (int)y;}// 连接顶点绘制五角星draw_line(fb, points[0], points[1], points[4], points[5], color);draw_line(fb, points[4], points[5], points[8], points[9], color);draw_line(fb, points[8], points[9], points[2], points[3], color);draw_line(fb, points[2], points[3], points[6], points[7], color);draw_line(fb, points[6], points[7], points[0], points[1], color);
}// 释放framebuffer资源
void cleanup_fb_device(fb_device_t *fb) {if (fb->fbp) {munmap(fb->fbp, fb->screen_size);fb->fbp = NULL;}if (fb->fd > 0) {close(fb->fd);fb->fd = 0;}if (fb->device_path) {free(fb->device_path);fb->device_path = NULL;}
}int main(int argc, char *argv[]) {fb_device_t fb = {0};color_t bg_color = {0}; // 背景颜色color_t draw_color = {0}; // 绘制颜色uint8_t bg_r = 0, bg_g = 0, bg_b = 0; // 默认背景色为黑色uint8_t dr_r = 255, dr_g = 255, dr_b = 255; // 默认绘制颜色为白色int i; // 在函数开头声明变量// 解析命令行参数const char *device_path = "/dev/fb0";// 解析设备路径if (argc > 1) {device_path = argv[1];}// 解析背景色参数if (argc > 4 && strcmp(argv[1], "-bg") == 0) {bg_r = atoi(argv[2]);bg_g = atoi(argv[3]);bg_b = atoi(argv[4]);argc -= 4;argv += 4;}// 解析绘制颜色参数if (argc > 3 && strcmp(argv[1], "-color") == 0) {dr_r = atoi(argv[2]);dr_g = atoi(argv[3]);dr_b = atoi(argv[4]);argc -= 4;argv += 4;}// 初始化设备if (init_fb_device(&fb, device_path) < 0) {return EXIT_FAILURE;}// 打印设备信息printf("Framebuffer设备: %s\n", fb.device_path);printf("分辨率: %dx%d, 像素深度: %d位\n", fb.vinfo.xres, fb.vinfo.yres, fb.vinfo.bits_per_pixel);// 设置背景颜色set_color(&bg_color, bg_r, bg_g, bg_b, 255);printf("背景颜色: RGB(%d, %d, %d)\n", bg_r, bg_g, bg_b);// 设置绘制颜色set_color(&draw_color, dr_r, dr_g, dr_b, 255);printf("绘制颜色: RGB(%d, %d, %d)\n", dr_r, dr_g, dr_b);// 映射内存if (map_fb_memory(&fb) < 0) {cleanup_fb_device(&fb);return EXIT_FAILURE;}printf("成功映射内存,开始填充背景色...\n");// 填充背景色if (fill_background(&fb, bg_color) < 0) {cleanup_fb_device(&fb);return EXIT_FAILURE;}printf("背景色填充完成,开始绘制图形...\n");// 计算屏幕中心和尺寸int center_x = fb.vinfo.xres / 2;int center_y = fb.vinfo.yres / 2;int size = fb.vinfo.xres < fb.vinfo.yres ? fb.vinfo.xres : fb.vinfo.yres;int half_size = size / 2;// 绘制横线draw_hline(&fb, 100, fb.vinfo.xres - 100, center_y - half_size + 50, draw_color);printf("已绘制横线\n");sleep(3); // 等待3秒以便查看效果// 绘制竖线draw_vline(&fb, center_x - half_size + 50, 100, fb.vinfo.yres - 100, draw_color);printf("已绘制竖线\n");sleep(3); // 等待3秒以便查看效果// 绘制圆形draw_circle(&fb, center_x, center_y, half_size - 100, draw_color);printf("已绘制圆形\n");sleep(3); // 等待3秒以便查看效果// 绘制三角形draw_triangle(&fb, center_x - 100, center_y + 50, center_x + 100, center_y + 50, center_x, center_y - 100, draw_color);printf("已绘制三角形\n");sleep(3); // 等待3秒以便查看效果// 绘制正方形draw_square(&fb, center_x - 80, center_y - 80, 160, draw_color);printf("已绘制正方形\n");sleep(3); // 等待3秒以便查看效果// 绘制五角星draw_star(&fb, center_x, center_y + 150, 100, 50, draw_color);printf("已绘制五角星\n");sleep(3); // 等待3秒以便查看效果printf("所有图形绘制完成!\n");printf("提示: 按Ctrl+C退出程序,图形将保留在屏幕上。\n");sleep(5); // 等待5秒以便查看效果// 释放资源cleanup_fb_device(&fb);return EXIT_SUCCESS;
}