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

linux编程----文件(framebuffer)

1、Framebuffer 基本概念

  1. 本质

    • Linux 内核提供的显示设备抽象层

    • 将显存映射为线性内存空间(设备文件:/dev/fbX)

    • 应用程序通过读写内存直接控制屏幕像素

2.核心结构

struct fb_var_screeninfo { // 可变参数
__u32 xres;          // 可视区域宽(像素)
__u32 yres;          // 可视区域高
__u32 xres_virtual;  // 虚拟缓冲区宽
__u32 yres_virtual;  // 虚拟缓冲区高
__u32 bits_per_pixel;// 像素深度(16/24/32)
// ... 其他参数
};

3.工作流程

打开显示设备(/dev/fb0)
获取显示设备相关参数(分辨率,像素格式)---》ioctl
建立显存空间和用户空间的内存映射
向映射的用户空间写入RGB颜色值
解除映射关系
关闭显示设备

2、关键代码实现解析

1. 初始化流程 (init_fb
  • 关键点

    • xres_virtual 可能大于 xres(实现多缓冲)

    • 像素深度决定颜色格式:

      • 16位:RGB565(R:5位, G:6位, B:5位)

      • 32位:ARGB8888(含Alpha通道)

相关代码:

int init_fb(char *devname) {// 1. 打开设备fb = open(devname, O_RDWR);  // 示例:open("/dev/fb0", ...)// 2. 获取屏幕参数ioctl(fb, FBIOGET_VSCREENINFO, &vinfo);// 3. 内存映射size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fb, 0);
}
2. 像素绘制算法 (draw_point)
  • 地址计算offset = (y * 虚拟宽度 + x) * 像素字节数

  • 内存布局:               

    像素(0,0) | 像素(1,0) | ... | 像素(W-1,0)
    像素(0,1) | 像素(1,1) | ... | 像素(W-1,1)
    ... 

相关代码

// 32位色模式
*(unsigned int*)(pmem + (y * vinfo.xres_virtual + x) * 4) = color;// 16位色模式
*(unsigned short*)(pmem + (y * vinfo.xres_virtual + x) * 2) = color;
3. 图形绘制算法

(1) 圆形绘制 (draw_Circle)

  • 原理:参数方程离散化(x=r·cosθ, y=r·sinθ)

  • 优化点:可改用Bresenham算法避免浮点运算

相关代码:

for(int angle = 0; angle <= 360; angle++) {int x0 = x + r * cos(angle * PI/180);int y0 = y + r * sin(angle * PI/180);draw_point(x0, y0, color);
}

(2) BMP图片绘制 (draw_bmp)

  • BMP特性

    • 文件头54字节

    • 像素存储顺序:从下到上扫描线

    • 颜色排列:BGR(非RGB)

相关代码:

// 颜色转换(24位BMP -> 目标格式)
if(vinfo.bits_per_pixel == 32) {col = (r << 16) | (g << 8) | b;  // RGB888
} else {col = ((r>>3)<<11) | ((g>>2)<<5) | (b>>3); // RGB565
}

(3) 字符绘制 (draw_word)

  • 点阵结构

    • 每字节代表8个水平像素点(MSB在最左)

    • 数组排列:行优先存储

相关代码:

for(int j=0; j<h; j++) {       // 行循环unsigned char byte = pword[i + j*w];for(int bit=0; bit<8; bit++) { // 位循环if(byte & 0x80)        // 检测最高位draw_point(x+i*8+bit, y+j, color);byte <<= 1;            // 移位检测下一位}
}
4相关函数

void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
功能:建立内存映射
参数:
addr :映射的用户空间首地址  
NULL:让操作系统自己分配用户空间
length:要映射的空间大小
prot: 操作权限
PROT_READ  Pages may be read.
PROT_WRITE Pages may be written
flag : MAP_SHARED
fd:显示设备文件描述符
offset:偏移量
0:从显存开头映射
返回值:
成功:映射的用户空间首地址
失败:MAP_FAILED((void *)-1)

3、使用注意事项

1.权限问题:sudo chmod 666 /dev/fb0  # 避免权限错误

2.性能优化:

  • 避免单点绘制(批量操作内存块)

  • 使用双缓冲机制减少闪烁:

    // 切换显示缓冲区
    vinfo.yoffset = next_buffer * screen_height;
    ioctl(fb, FBIOPAN_DISPLAY, &vinfo);

    3.常见问题处理:

  • 花屏:检查像素格式是否匹配(RGB565 vs ARGB8888)

  • 偏移错误:确认BMP文件头解析正确

  • 内存泄漏:确保munmap配对mmap

4.framebuffer相关操作的封装函数

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include "framebuffer.h"
#include <math.h>void *pmem = NULL;
int fb;
struct fb_var_screeninfo vinfo;int init_fb(char *devname)
{//1. 打开显示设备(/dev/fb0)fb = open(devname, O_RDWR);if (-1 == fb){perror("open fb error");return -1;}//2. 获取显示设备相关参数(分辨率,像素格式)int ret = ioctl(fb, FBIOGET_VSCREENINFO, &vinfo);if (ret < 0){perror("ioctl error");return -1;}printf("xres = %d, yres = %d\n", vinfo.xres, vinfo.yres);printf("xres_virtual = %d, yres_virtual = %d\n", vinfo.xres_virtual, vinfo.yres_virtual);printf("bits_per_pixel = %d\n", vinfo.bits_per_pixel);//3. 建立显存空间和用户空间的内存映射size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fb, 0);if (pmem == MAP_FAILED){perror("mmap error");return -1;}return 0;
}int uninit_fb()
{//5. 解除映射关系//6. 关闭显示设备size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;munmap(pmem, len);close(fb);}//绘制一个点
void draw_point(int x, int y, unsigned int col)
{if (x >= vinfo.xres || y >= vinfo.yres){return ;}if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;*(p+vinfo.xres_virtual*y+x) = col;}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;*(p+vinfo.xres_virtual*y+x) = col;}
}//绘制一条线
void draw_x_line( int y, int x_begin, int x_end, unsigned int col)
{int i;for(i = x_begin; i < x_end; ++i){draw_point(i, y, col);}}void draw_y_line( int x, int y_begin, int y_end, unsigned int col)
{int i;for(i = y_begin; i < y_end; ++i){draw_point(x, i, col);}
}//绘制矩形
void draw_rect(int x_begin, int y_begin, int weight, int hight, unsigned int col )
{   draw_x_line(y_begin, x_begin, x_begin + weight, col);draw_y_line(x_begin, y_begin, y_begin + hight, col);draw_x_line(y_begin + hight, x_begin, x_begin + weight, col);draw_y_line(x_begin + weight, y_begin, y_begin + hight, col);
}//绘制圆
void draw_Circle(int x, int y, int r, unsigned int col)
{int x0 = 0;int y0 = 0;int si = 0;for (si = 0; si <= 360; si++){x0 = r * sin(PI * 2 / 360 * si) + x; y0 = r * cos(PI * 2 / 360 * si) + y;draw_point(x0, y0, col);}
}//获取bmp的文件头和图片头
int get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo)
{FILE *fp = fopen(bmpname, "r");if (NULL == fp){perror("fopen error");return -1;}fread(pheadinfo, sizeof(Bmp_file_head_t), 1, fp);fread(pbmpinfo, sizeof(Bmp_info_t), 1, fp);fclose(fp);return 0;
}//绘制图片
void draw_bmp(int x, int y, char *bmpname)
{Bmp_file_head_t headinfo;Bmp_info_t bmpinfo;get_bmp_head_info(bmpname, &headinfo, &bmpinfo);int fd = open(bmpname, O_RDONLY);if (-1 == fd){perror("open bmp error");return ;}lseek(fd, 54, SEEK_SET);unsigned char *buff = malloc(bmpinfo.biHeight*bmpinfo.biWidth*bmpinfo.biBitCount/8);read(fd, buff, bmpinfo.biHeight*bmpinfo.biWidth*bmpinfo.biBitCount/8);close(fd);unsigned char *p = buff;unsigned char r, g, b;for (int j = bmpinfo.biHeight-1; j >= 0; j--){for (int i = 0; i < bmpinfo.biWidth; i++){b = *p;++p;g = *p;++p;r = *p;++p;if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int col = (r << 16) | (g << 8) | (b << 0);draw_point(i+x, j+y, col);}else if  (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short col = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);draw_point(i+x, j+y, col);}}}free(buff);}//绘制字符
void draw_word(int x, int y, unsigned char *pword, int w, int h, unsigned int col)
{for (int j = 0; j < h; j++){for (int i = 0; i < w; i++){unsigned char tmp = pword[i+j*w];for (int k = 0; k < 8; k++){if (tmp & 0x80){draw_point(x+i*8+k, y+j, col);}else{}tmp = tmp << 1;}}}
}

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

相关文章:

  • 正则表达式解析(三)
  • 方法论基础。
  • 与Deepseek对话了解无线电通信知识
  • 自动曝光算法参考
  • Linux Framebuffer(帧缓冲)与基本 UI 绘制技术
  • GitHub宕机时的协作方案
  • 力扣 hot100 Day72
  • Transformer开端
  • 有效涂色问题-二维dp
  • C++进阶之lambda三种回调方式性能差异(四百二十七)
  • 【13】Transformers快速入门:Transformers 分词器 (Tokenizer) 实战?
  • 哈希表之两个数组的交集(leetcode349)
  • 智能合约开发全流程实战指南
  • 【LeetCode】4. 寻找两个正序数组的中位数
  • 芯伯乐300kHz降压DC/DC转换器XBL4005:4.5V~40V宽电压范围,5A大电流高效输出
  • 三伍微电子GSR2406 IoT FEM 2.4G PA 射频前端模组芯片
  • 深入解析C语言嵌套结构体的内存管理与操作实践
  • linux_网络层-ip协议
  • [系统架构设计师]信息安全技术基础知识(三)
  • SpringBoot3+ Elasticsearch8 Spring-data-Elasticsearch使用
  • 多模态数据集分级方案设计与实现
  • 容器基础镜像制作
  • ETLCloud批流一体化体现在哪
  • 【Python】Python 函数基本介绍(详细版)​
  • 版图设计学习2_掌握PDK中的层定义(工艺文档精读)
  • DAY39打卡
  • 【运维进阶】管理变量和事实
  • 哥斯拉--安装、使用
  • graf示教界面技术累积
  • 数据结构摘星题库800题笔记 第2章线性表