Bootstrap

Framebuffer(帧缓冲)

         Framebuffer(帧缓冲)是Linux系统中为显示设备提供的一套应用程序接口,它将显存抽象为一种设备,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。

        原理:通过内存映射技术向显存空间中写入rgb颜色值;

1. 基本概念

  • 定义:Framebuffer,可以译作“帧缓冲”,是Linux内核为显示设备提供的一个接口,它将显存抽象后供用户态进程使用。
  • 作用:作为显示内存的一个映像,Framebuffer允许应用程序直接对其进行读写操作,从而控制屏幕上的显示内容。

2. 组成部分

  • 颜色缓冲区:存储每个像素的颜色信息,如RGBA值。
  • 深度缓冲区:存储每个像素的深度信息,用于处理3D场景的遮挡问题。
  • 模板缓冲区:用于实现图形遮罩技术,控制哪些像素可以被绘制。
  • 多重采样缓冲区(MSAA):用于减少锯齿状边缘的效果,提高图像质量。

3. 使用方式

        1.打开显示设备(/dev/fbo);

        2.获取显示设备相关参数(分辨率,位深度);

        3.建立内存映射;

        4.写入rgb颜色值;

        5.解除映射;

        6.关闭显示设备;

4. 应用场景

  • 图形界面显示:在Linux桌面系统中,X Window服务器利用Framebuffer进行窗口的绘制。
  • 嵌入式系统:在嵌入式Linux系统中,Framebuffer是控制LCD显示的主要方式。
  • 游戏开发:在游戏开发中,Framebuffer用于渲染游戏画面,并通过更新Framebuffer的内容来实现动画效果。

5. 优点与缺点

  • 优点:
    • 提供了对图形设备的硬件抽象,简化了图形编程的复杂性。
    • 支持离屏渲染,提高了图形处理的性能。
    • 允许应用程序直接控制屏幕显示内容,灵活性高。
  • 缺点:
    • 需要真正的显卡驱动支持,且所有显示任务都由CPU完成,可能导致CPU负担较重。
    • 对物理显存的位置、换页机制等具体细节进行了抽象,但开发者仍需了解相关硬件知识以进行高效编程。

6. 编程接口

  • open函数:用于打开Framebuffer设备文件(如/dev/fb0)。
  • ioctl函数:用于获取和设置Framebuffer的参数,如分辨率、颜色深度等。
  • mmap函数:用于将Framebuffer映射到进程的地址空间,以便进行读写操作。

7.示例

#include "framebuffer.h"
#include <linux/fb.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <math.h>
void *pmem;
struct fb_var_screeninfo vinf;

int init_fb(char *devname)
{
	//1. 打开显示设备
	int fd = open(devname, O_RDWR);	
	if (-1 == fd)
	{
		perror("fail open fb");
		return -1;
	}
	
	//2、获取显示设备相关参数 分辨率 位深度
	int ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinf);
	if (-1 ==ret)
	{
		perror("fail ioctl");
		return -1;
	}
	
	printf("xres = %d, yres = %d\n", vinf.xres, vinf.yres);
	printf("xres_virtual = %d, yres_virtual = %d\n", vinf.xres_virtual, vinf.yres_virtual);
	printf("bits_per_pixel : %d\n", vinf.bits_per_pixel);

	size_t len = vinf.xres_virtual * vinf.yres_virtual * vinf.bits_per_pixel/8;
	//3, 建立显存和用户空间的映射关系
	pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if ((void *)-1 == pmem)
	{
		perror("fail mmap");
		return -1;
	}
	

	return fd;
}

void draw_point(int x, int y, unsigned int col)
{
	if (x >= vinf.xres || y >= vinf.yres)
	{
		return ;
	}
	if (vinf.bits_per_pixel == RGB888_FMT)
	{
		unsigned int *p = (unsigned int *)pmem;
		*(p + y * vinf.xres_virtual + x) = col;
	}
	else if (vinf.bits_per_pixel == RGB565_FMT)
	{
		unsigned short *p  = (unsigned short *)pmem;	
		*(p + y * vinf.xres_virtual + x) = col;
	}
	return ;
}
void draw_x_line(int x, int y, int len, unsigned int col)
{
	if (x >= vinf.xres || y >= vinf.yres)
	{
		return ;
	}
	for (int i = x; i < x+len; i++)
	{
		draw_point(i, y, col);
	}
    return;
}
void draw_y_line(int x, int y, int len, unsigned int col)
{
	if (x >= vinf.xres || y >= vinf.yres)
	{
		return ;
	}
	for (int i = y; i < y+len; i++)
	{
		draw_point(x, i, col);
	}
    return;
}

void draw_bias(int x, int y, int len, unsigned int col)
{
	if (x >= vinf.xres || y >= vinf.yres)
	{
		return ;
	}
    int i=0;
    while(i<len)
    {   
		draw_point(x, y, col);
        ++x;
        ++y;
        ++i;
    }
}
void draw_circle(int x, int y, int r, unsigned int col)
{
	int x0, y0;
	for (int i = 0; i <= 360; ++i)
	{
		x0 = r * cos(2 * 3.1415/360 * i) + x;
		y0 = r * sin(2 * 3.1415/360 * i) + y;
		draw_point(x0, y0, col);
		draw_point(x0+1, y0, col);
		draw_point(x0, y0+1, col);
		draw_point(x0-1, y0, col);
		draw_point(x0, y0-1, col);
	}
}

void draw_rectangle(int x,int y,int len,int wide,unsigned int col)
{
	if (x >= vinf.xres || y >= vinf.yres)
	{
		return ;
	}
    draw_x_line(x,y,len,col);
    draw_y_line(x,y,wide,col);
    draw_x_line(x,y+wide,len,col);
    draw_y_line(x+len,y,wide,col);
}

void draw_clear(unsigned int col)
{
    for(int i =0;i<vinf.xres_virtual;++i)
    {
        for(int j=0;j<vinf.yres_virtual;++j)
        {
            draw_point(i,j,col);
        }
    }
}
void uninit_fb(int fd)
{

	size_t len = vinf.xres_virtual * vinf.yres_virtual * vinf.bits_per_pixel/8;
	munmap(pmem, len);
	close(fd);
}


;