当前位置: 首页 > news >正文

【Linux】Framebuffer入门及练手

以下内容来自【腾讯元宝】


Linux framebuffer 是一个强大且有趣的工具,它能让你直接与屏幕的像素“对话”。下面这份教程将带你系统地了解它。

📖 初识 Framebuffer

可以把 framebuffer(帧缓冲)想象成屏幕内容在内存里的一个“镜像”或“画布”。你向这块内存区域写入什么数据,屏幕上就会立刻显示对应的图像。在 Linux 系统中,这个“画布”通常以设备文件的形式出现,比如 /dev/fb0(第一个显示设备)或 /dev/fb1(第二个显示设备)。它的核心价值在于,无需依赖任何图形界面(如 X Window 或 Wayland),就能直接控制屏幕显示,这使得它在嵌入式系统、服务器或图形驱动开发中非常有用。

⚙️ 使用 Framebuffer 的步骤

使用 framebuffer 进行绘图,通常遵循以下标准流程,其核心关系如下图所示:

打开设备 /dev/fb0
获取设备信息
内存映射 mmap
在映射内存中绘图
清理资源

下面我们详细讲解每一步的具体操作。

1. 打开设备

这是第一步,就像你要作画得先进入画室一样。通过 open 系统调用打开 framebuffer 设备文件。

int fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb == -1) {perror("Error opening framebuffer device");exit(1);
}
2. 获取屏幕信息

在开始绘画前,你需要知道“画布”有多大,用什么颜料。通过 ioctl 获取这些信息。

#include <linux/fb.h> // 需要包含这个头文件struct fb_var_screeninfo vinfo; // 可变信息(如当前分辨率)
struct fb_fix_screeninfo finfo; // 固定信息(如显存物理地址)ioctl(fd_fb, FBIOGET_VSCREENINFO, &vinfo); // 获取可变信息
ioctl(fd_fb, FBIOGET_FSCREENINFO, &finfo); // 获取固定信息// 打印信息示例
printf("Resolution: %dx%d, %d bpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
printf("Virtual resolution: %dx%d\n", vinfo.xres_virtual, vinfo.yres_virtual);
printf("Line length: %d bytes\n", finfo.line_length);

关键参数说明:

  • xres, yres: 屏幕的物理分辨率。
  • xres_virtual, yres_virtual: 虚拟分辨率。虚拟分辨率的高度(yres_virtual)可能大于物理分辨率的高度(yres),这通常是为了实现双缓冲(一页显示,另一页绘制),以减少闪烁。
  • bits_per_pixel: 每个像素用多少位表示,常见有 16位(RGB565)、24位(RGB888)、32位(ARGB8888)。
  • line_length: 一行像素在内存中占用的总字节数(通常 >= xres * bits_per_pixel / 8)。
3. 内存映射 (mmap)

显存是内核空间的内存,应用程序不能直接访问。mmap 函数可以将这块显存映射到应用程序的用户空间地址,这样你就可以像操作普通内存一样直接读写屏幕内容了。

// 计算需要映射的内存大小
// 注意:通常用虚拟分辨率计算,以适应双缓冲等情况
size_t screensize = vinfo.yres_virtual * finfo.line_length;// 执行映射
char *fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fbp == MAP_FAILED) {perror("Error mapping framebuffer device to memory");exit(1);
}
4. 绘制像素点

现在,你可以直接向映射的内存写入数据来画点了。关键在于根据不同的色彩深度正确计算像素位置和颜色值。

void draw_pixel(int x, int y, unsigned int color) {// 边界检查if (x >= vinfo.xres || y >= vinfo.yres) return;// 计算指定像素在映射内存中的位置// 注意:这里使用 finfo.line_length 来计算偏移量更准确long location = x * (vinfo.bits_per_pixel / 8) + y * finfo.line_length;// 根据色彩深度写入颜色值switch (vinfo.bits_per_pixel) {case 16: { // RGB565unsigned short *pixel = (unsigned short *)(fbp + location);// 将24位RGB颜色(0xRRGGBB)转换为16位RGB565unsigned int r = (color >> 16) & 0xff;unsigned int g = (color >> 8) & 0xff;unsigned int b = color & 0xff;*pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);break;}case 24: // 可能会遇到,但存储方式可能因硬件而异case 32: { // 通常为ARGB8888或RGBA8888等,这里以简单处理为例unsigned int *pixel = (unsigned int *)(fbp + location);*pixel = color; // 直接写入颜色值break;}default:printf("Unsupported bpp: %d\n", vinfo.bits_per_pixel);}
}
5. 清理资源

绘图结束后,别忘记解除映射并关闭设备。

munmap(fbp, screensize);
close(fd_fb);

🎨 综合实例:绘制渐变图形

掌握了画点函数,就可以绘制更复杂的图形了。下面是一个简单的综合示例,它在屏幕上绘制一个渐变的色条。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/fb.h>int main() {int fd_fb;struct fb_var_screeninfo vinfo;struct fb_fix_screeninfo finfo;char *fbp;// 1. 打开设备fd_fb = open("/dev/fb0", O_RDWR);if (fd_fb == -1) { perror("open"); exit(1); }// 2. 获取信息if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &vinfo)) { perror("ioctl vinfo"); exit(1); }if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &finfo)) { perror("ioctl finfo"); exit(1); }// 3. 内存映射size_t screensize = vinfo.yres_virtual * finfo.line_length;fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);if (fbp == MAP_FAILED) { perror("mmap"); exit(1); }// 4. 绘制渐变图形for (int y = 0; y < vinfo.yres; y++) {for (int x = 0; x < vinfo.xres; x++) {// 根据位置计算颜色,产生渐变效果unsigned int r = (x * 255) / vinfo.xres;unsigned int g = (y * 255) / vinfo.yres;unsigned int b = 100;unsigned int color = (r << 16) | (g << 8) | b; // 组合成24位RGB颜色// 调用画点函数// 注意:这里需要将上面代码中的 draw_pixel 函数实现放在这里或单独定义long location = x * (vinfo.bits_per_pixel / 8) + y * finfo.line_length;if (vinfo.bits_per_pixel == 16) {/* ... RGB565 转换和写入 ... */} else if (vinfo.bits_per_pixel == 32) {*((unsigned int*)(fbp + location)) = color;}}}// 留点时间查看效果sleep(5);// 5. 清理资源munmap(fbp, screensize);close(fd_fb);return 0;
}

💡 实用技巧与注意事项

  • 编译:编译上述代码时,需要链接数学库(如果使用了数学函数),例如 gcc -o fb_test fb_test.c
  • 运行权限:运行程序通常需要 root 权限,因为直接访问了设备文件,例如 sudo ./fb_test
  • 清屏:清屏操作很简单,通常用 memset 将映射的内存区域填充为单一颜色(如黑色)即可。
    memset(fbp, 0x00, screensize); // 填充为黑色
    
  • 双缓冲:如果发现绘制过程中屏幕闪烁,可能是因为使用了双缓冲。在双缓冲机制中,绘制完成后,通常需要通过 ioctl 设置 vinfo.yoffset 来切换当前显示页。

希望这篇教程能帮助你轻松上手 Linux framebuffer 编程!

http://www.dtcms.com/a/492066.html

相关文章:

  • 做网站和网页有区别吗专业做二手房的网站
  • Zabbix监控使用指南
  • 诺盾网站建设服装库存管理软件
  • js 做网站兰州网站建设公
  • FastMonitor - 网络流量监控与威胁检测工具
  • 漯河百度做网站电话推广软文发布平台
  • 山东建设银行官方网站网站的制作建站人
  • Nodejs版本切换NVM
  • 自动伸缩:HPA自定义指标,业务指标驱动扩缩?
  • 购买帝国cms做网站代理进了网站的后台系统 怎么改公司的网站
  • 智能文档抽取技术:将非结构化文档转化为结构化数据,解决档案管理中的信息沉睡、编目低效等问题
  • re综合题|双指针
  • 网站突然没有收录wordpress重置query循环
  • 虎虎应用隐藏凭 “免费 + 服务” 破局,重新定义隐私保护体验
  • 网站结构优化怎么做wordpress加载速度太慢
  • C++语言编程规范-并发
  • 金华网站建设黄页wordpress修改后台样式
  • 网站锚文本wordpress 增加 推荐
  • 一周内从0到1开发一款安卓应用商店
  • 谷歌网站怎么做推广专业图库网站 西安
  • 自己做网站 教程韩国网页游戏网站
  • 三明交通建设集团网站飞鸟加速器
  • 【B树与B+树详解】
  • 哪个网站做ppt能赚钱个人养老保险12000元
  • 可以做兼职翻译的网站上海企业服务
  • LangExtract:基于LLM的信息抽取框架 学习笔记
  • 强化学习入门-3(AC)
  • Redis学习笔记-QuickList
  • C#循序渐进
  • 怎么做公司的官方网站网站做京东联盟