linux下framebuffer相关函数及知识点详解及整合运用

在 Linux 下,`framebuffer`(简称 `fb`)是一个提供硬件图形缓冲区的接口,允许用户应用程序直接访问图形设备的显示内存。它可以用于简单的图形显示操作,如直接向屏幕绘制像素、图形等。Framebuffer 的作用是让开发者可以直接操作屏幕上的像素,绕过图形服务器(如 X 或 Wayland),实现低级的图形操作。

主要涉及的知识点和相关函数

1. Framebuffer 设备文件
Framebuffer 设备通常在 `/dev/fb0`(主显示设备)下表示,可以使用 `open` 函数打开该设备,进行读写操作。  

int fd = open("/dev/fb0", O_RDWR);
if (fd == -1) {
    perror("Error: cannot open framebuffer device");
    exit(1);
}
 

2. `ioctl` 获取屏幕信息
使用 `ioctl` 函数来获取或设置 framebuffer 的相关信息,例如屏幕分辨率、位深度等。通过 `FBIOGET_VSCREENINFO` 可以获取可变屏幕信息(`fb_var_screeninfo` 结构体),包括屏幕的像素宽度、高度、颜色深度等。


struct fb_var_screeninfo vinfo;
if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo)) {
    perror("Error reading variable information");
    exit(1);
}
printf("Screen resolution: %dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
 

- `xres` 和 `yres`:屏幕的水平和垂直分辨率(单位是像素)。
- `bits_per_pixel`:每个像素所占用的位数,通常是 16、24 或 32。

3. `mmap` 内存映射 Framebuffer
为了直接操作 framebuffer 内存,我们可以使用 `mmap` 将 framebuffer 的内存映射到用户空间。这样,我们可以像操作普通数组一样操作屏幕上的像素。


size_t screensize = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;
void *fbmem = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (fbmem == MAP_FAILED) {
    perror("Error: Failed to map framebuffer device to memory");
    exit(1);
}
 

- `screensize`:计算显示屏内存所需的字节数,等于分辨率乘以每像素的字节数。
- `mmap` 函数返回屏幕内存的指针,可以通过该指针直接访问 framebuffer。

4. 绘制像素
在 framebuffer 上绘制像素时,首先需要知道屏幕的颜色模式(例如 RGB888 或 RGB565),然后根据坐标计算相应的内存位置,并向该位置写入颜色值。


void draw_point(int x, int y, unsigned int color)
{
    long location = (x + vinfo.xres_virtual * y) * (vinfo.bits_per_pixel / 8);
    *((unsigned int *)(fbmem + location)) = color;
}

- `location`:计算给定坐标在 framebuffer 内存中的位置。
- `color`:颜色值根据屏幕的颜色深度(如 24 位或 16 位)进行设定。

5. 颜色格式
常见的颜色格式有:
- RGB565:每个像素 16 位,5 位用于红色,6 位用于绿色,5 位用于蓝色。
- RGB888:每个像素 24 位,8 位用于红色,8 位用于绿色,8 位用于蓝色。

根据不同的颜色格式,设置颜色时需要考虑每种颜色所占用的位数。例如,对于 RGB565:

unsigned short color = ((red & 0x1F) << 11) | ((green & 0x3F) << 5) | (blue & 0x1F);
 

6. 清屏操作
清屏可以通过将整个 framebuffer 的内存区域填充为指定颜色来实现。


void clear_screen(unsigned int color)
{
    for (int y = 0; y < vinfo.yres_virtual; y++) {
        for (int x = 0; x < vinfo.xres_virtual; x++) {
            draw_point(x, y, color);
        }
    }
}
```

7. 关闭 framebuffer
在程序结束时,应该调用 `munmap` 和 `close` 关闭 framebuffer 设备,释放资源。


munmap(fbmem, screensize);
close(fd);
 

整合运用:绘制基本图形

下面是一个整合了上述知识点的代码示例,演示如何打开 framebuffer 设备,绘制点、线、矩形和圆。


#include <linux/fb.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

struct fb_var_screeninfo vinfo;
void *fbmem;

int init_fb(const char *devname)
{
    int fd = open(devname, O_RDWR);
    if (fd == -1) {
        perror("Error: cannot open framebuffer device");
        return -1;
    }

    if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo)) {
        perror("Error reading variable information");
        return -1;
    }

    size_t screensize = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;
    fbmem = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (fbmem == MAP_FAILED) {
        perror("Error: Failed to map framebuffer device to memory");
        return -1;
    }
    return fd;
}

void draw_point(int x, int y, unsigned int color)
{
    if (x >= vinfo.xres || y >= vinfo.yres) return;
    long location = (x + vinfo.xres_virtual * y) * (vinfo.bits_per_pixel / 8);
    *((unsigned int *)(fbmem + location)) = color;
}

void draw_line(int x0, int y0, int x1, int y1, unsigned int color)
{
    int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
    int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
    int err = dx + dy, e2;

    while (1) {
        draw_point(x0, y0, color);
        if (x0 == x1 && y0 == y1) break;
        e2 = 2 * err;
        if (e2 >= dy) { err += dy; x0 += sx; }
        if (e2 <= dx) { err += dx; y0 += sy; }
    }
}

void draw_circle(int xc, int yc, int r, unsigned int color)
{
    int x = 0, y = r, d = 3 - 2 * r;
    while (x <= y) {
        draw_point(xc + x, yc + y, color);
        draw_point(xc - x, yc + y, color);
        draw_point(xc + x, yc - y, color);
        draw_point(xc - x, yc - y, color);
        draw_point(xc + y, yc + x, color);
        draw_point(xc - y, yc + x, color);
        draw_point(xc + y, yc - x, color);
        draw_point(xc - y, yc - x, color);
        if (d < 0) {
            d += 4 * x + 6;
        } else {
            d += 4 * (x - y) + 10;
            y--;
        }
        x++;
    }
}

void clear_screen(unsigned int color)
{
    for (int y = 0; y < vinfo.yres; y++) {
        for (int x = 0; x < vinfo.xres; x++) {
            draw_point(x, y, color);
        }
    }
}

int main()
{
    int fd = init_fb("/dev/fb0");
    if (fd == -1) return 1;

    clear_screen(0x000000);  // 清屏为黑色

    draw_line(100, 100, 500, 300, 0xFF0000); // 画一条红色的线
    draw_circle(300, 300, 100, 0x00FF00);    // 画一个绿色的圆

    sleep(10); // 显示 10 秒
    munmap(fbmem, vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8);
    close(fd);

    return 0;
}
 

总结
- Framebuffer 提供了一种直接控制屏幕显示的方式。
- 通过 `ioctl` 获取屏幕信息,使用 `mmap` 映射内存

,并直接操作该内存,可以实现图形的绘制。
- 基本图形操作如绘制点、线、圆、矩形等都可以通过简单的算法在 framebuffer 上实现。

该示例展示了在 Linux 中如何通过 framebuffer 直接操控图形显示,适用于嵌入式开发和不依赖 X 窗口系统的显示场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值