3. 填充单色背景

填充单色背景 学习卡片

任务目标

本案例实现Linux Framebuffer驱动的单色背景填充:将整个屏幕填充为指定颜色(如红色),以此验证Framebuffer的mmap映射与像素写入功能是否正常。

环境与依赖

  • Linux系统(含/dev/fb0设备节点,需有读写权限)
  • 内核已启用Framebuffer驱动(如DRM或simplefb)
  • gcc编译器

核心实现

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

int main(int argc, char *argv[]) {
    int fb_fd;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    char *fbp;
    long screensize;
    unsigned int color = 0x00FF0000;  // 默认红色 (ARGB8888)
    
    // 解析命令行参数:可指定颜色值(十六进制,如 0x00FF0000)
    if (argc > 1) {
        color = (unsigned int)strtoul(argv[1], NULL, 0);
    }
    
    // 打开Framebuffer设备
    fb_fd = open("/dev/fb0", O_RDWR);
    if (fb_fd == -1) {
        perror("打开 /dev/fb0 失败");
        return 1;
    }
    
    // 获取屏幕可变信息(分辨率、位深等)
    if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
        perror("获取可变屏幕信息失败");
        close(fb_fd);
        return 1;
    }
    
    // 获取固定信息(smem_len表示显存大小)
    if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
        perror("获取固定屏幕信息失败");
        close(fb_fd);
        return 1;
    }
    
    // 计算显存总大小(字节)
    screensize = finfo.smem_len;
    
    // 将显存映射到用户空间
    fbp = (char *)mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    if (fbp == MAP_FAILED) {
        perror("mmap 失败");
        close(fb_fd);
        return 1;
    }
    
    // 计算每像素字节数
    int bytes_per_pixel = vinfo.bits_per_pixel / 8;
    
    // 将颜色值转换为与当前像素格式匹配的存储值
    // 此处假设ARGB8888格式(32位),若实际格式不同需调整
    unsigned int pixel_value = color;
    
    // 填充整个屏幕
    for (int y = 0; y < vinfo.yres; y++) {
        for (int x = 0; x < vinfo.xres; x++) {
            long offset = (x + vinfo.xoffset) * bytes_per_pixel + 
                          (y + vinfo.yoffset) * finfo.line_length;
            // 按每像素字节数写入
            for (int b = 0; b < bytes_per_pixel; b++) {
                fbp[offset + b] = (pixel_value >> (b * 8)) & 0xFF;
            }
        }
    }
    
    // 清理资源
    munmap(fbp, screensize);
    close(fb_fd);
    
    printf("屏幕填充完成:分辨率 %dx%d,颜色 0x%08X\n", 
           vinfo.xres, vinfo.yres, color);
    return 0;
}

编译与运行

# 编译
gcc -o fill_screen fill_screen.c

# 运行(默认填充红色)
./fill_screen

# 指定颜色填充(例如绿色 0x00FF00)
./fill_screen 0x0000FF00

验证方法

  1. 运行程序后,屏幕应整体变为指定颜色(默认红色),无条纹或花屏现象。
  2. 若屏幕无变化,检查:
    • 当前终端是否处于图形界面(需在纯文本终端或关闭X服务后测试)
    • 设备节点权限:ls -l /dev/fb0,必要时chmod 666 /dev/fb0
    • 像素格式是否匹配:程序默认按ARGB8888处理,若实际为RGB565(16位),需修改写入逻辑
  3. 可通过fbset命令查看当前分辨率与位深,确认与程序读取的参数一致。

常见问题

  • 屏幕无变化:确认没有X Server占用Framebuffer,可切换到tty终端(Ctrl+Alt+F1~F6)测试。
  • 颜色显示不正确:不同屏幕的像素格式不同(RGB565、ARGB8888等),需根据vinfo.bits_per_pixel和vinfo.red/green/blue偏移量调整颜色值转换逻辑。
  • mmap失败:确认设备节点存在且当前用户有读写权限。