当前位置: 首页 > 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/490758.html

相关文章:

  • 深圳做网站公司有哪些公司英文购物网站模板下载
  • 力扣热题100道之560和位K的子数组
  • Pixel-Perfect Depth with Semantics-Prompted Diffusion Transformers,nips 2025
  • 网站可以换主机吗做外贸网站 用国外空间 还是 国内空间 区别
  • **SLAM技术:探索现代定位与地图构建的新纪元**在现代科技领域,同步定位与地图构建(SLAM)技术已成为机器人导航和自动驾驶等领
  • 环保教育展厅建设方案-VR垃圾分类体验游戏-垃圾分类拍拍乐
  • 网站空间怎么更换莱芜在线论坛最新消息
  • 龙岩做网站哪家好如何绑定网站域名
  • [Linux系统编程——Lesson14.基础IO:系统文件IO]
  • golang的一些技巧
  • 高性能 Go 语言带 TTL 的内存缓存实现:精确过期、自动刷新、并发安全
  • ML.NET机器学习框架基本流程介绍
  • Day32_【 NLP _2.RNN及其变体 _(2) LSTM】
  • 重庆建站模板代理怎么做p2p网站
  • iis配置网站是什么网站建设方案书阿里云模板
  • 【计算机视觉】SAM 3 技术深潜:从“分割万物”到“理解概念”的范式转移
  • 「深度学习笔记3」概率论深度解析:从不确定性到人工智能的桥梁
  • 齐河专业企业网站建设做网站引流到天猫
  • 技术贴!【谷歌浏览器】实用工具推荐之谷歌浏览器(Google Chrome)离线纯净版完全安装指南:告别广告与捆绑骚扰
  • Centos7 自建Umami-开源免费的网站访问流量统计分析平台
  • 申威架构安装Java 11 RPM包教程:java-11.0.7-swjdk-11u-8.ky10.sw_64.rpm详细安装步骤
  • 【STM32项目开源】基于STM32的人体健康监测系统
  • 一个做礼品的网站国外网站用什么dns
  • 东莞 网站建设网站定制制作公司
  • Python 线程 类比c++【python】
  • 舆情监测的底层逻辑与技术方法探析
  • 谈谈redis的持久化
  • 网站建设进度深圳网站建设制作营销
  • SSM高校学生社团管理系统n4pcu(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 强化学习_Paper_2000_Eligibility Traces for Off-Policy Policy Evaluation