关于linux读取显卡信息的方法-帧缓冲机制介绍

读取显卡信息,其实就是读取设备文件/dev/fb0,该文件对应Linux的framebuffer,在linux/fb.h文件内定义了两个结构体:

fb_fix_screeninfo和fb_var_screeninfo,fb_fix_screeninfo记录的是设备固定参数,fb_var_screeninfo记录的则是虚拟参数,下面先看看两个结构体的内容。

struct fb_fix_screeninfo {
	char id[16];			/* identification string eg "TT Builtin" */
	unsigned long smem_start;	/* Start of frame buffer mem */
					/* (physical address) */
	__u32 smem_len;			/* Length of frame buffer mem */
	__u32 type;			/* see FB_TYPE_*		*/
	__u32 type_aux;			/* Interleave for interleaved Planes */
	__u32 visual;			/* see FB_VISUAL_*		*/ 
	__u16 xpanstep;			/* zero if no hardware panning  */
	__u16 ypanstep;			/* zero if no hardware panning  */
	__u16 ywrapstep;		/* zero if no hardware ywrap    */
	__u32 line_length;		/* length of a line in bytes    */
	unsigned long mmio_start;	/* Start of Memory Mapped I/O   */
					/* (physical address) */
	__u32 mmio_len;			/* Length of Memory Mapped I/O  */
	__u32 accel;			/* Indicate to driver which	*/
					/*  specific chip/card we have	*/
	__u16 capabilities;		/* see FB_CAP_*			*/
	__u16 reserved[2];		/* Reserved for future compatibility */
};



struct fb_var_screeninfo {
	__u32 xres;			/* visible resolution		*/
	__u32 yres;
	__u32 xres_virtual;		/* virtual resolution		*/
	__u32 yres_virtual;
	__u32 xoffset;			/* offset from virtual to visible */
	__u32 yoffset;			/* resolution			*/

	__u32 bits_per_pixel;		/* guess what			*/
	__u32 grayscale;		/* 0 = color, 1 = grayscale,	*/
					/* >1 = FOURCC			*/
	struct fb_bitfield red;		/* bitfield in fb mem if true color, */
	struct fb_bitfield green;	/* else only length is significant */
	struct fb_bitfield blue;
	struct fb_bitfield transp;	/* transparency			*/	

	__u32 nonstd;			/* != 0 Non standard pixel format */

	__u32 activate;			/* see FB_ACTIVATE_*		*/

	__u32 height;			/* height of picture in mm    */
	__u32 width;			/* width of picture in mm     */

	__u32 accel_flags;		/* (OBSOLETE) see fb_info.flags */

	/* Timing: All values in pixclocks, except pixclock (of course) */
	__u32 pixclock;			/* pixel clock in ps (pico seconds) */
	__u32 left_margin;		/* time from sync to picture	*/
	__u32 right_margin;		/* time from picture to sync	*/
	__u32 upper_margin;		/* time from sync to picture	*/
	__u32 lower_margin;
	__u32 hsync_len;		/* length of horizontal sync	*/
	__u32 vsync_len;		/* length of vertical sync	*/
	__u32 sync;			/* see FB_SYNC_*		*/
	__u32 vmode;			/* see FB_VMODE_*		*/
	__u32 rotate;			/* angle we rotate counter clockwise */
	__u32 colorspace;		/* colorspace for FOURCC-based modes */
	__u32 reserved[4];		/* Reserved for future compatibility */
};

 我们先看fb_fix_screeninfo结构体里的参数:

id[16]        很明显,设备名称。

smem_start        frame buffer的内存地址,即显存的物理起始地址

smem_len        framebuffer的内存长度,也就是物理显存大小

type                   显卡的类型,共6个取值,如下:

        FB_TYPE_PACKED_PIXELS :

        填充式像素(Packed Pixels):在这种存储方式中,像素的各个颜色分量(如红色、绿色、蓝色等)被紧密地打包在一起,形成一个完整的像素值。这意味着每个像素值都包含了该像素所有颜色分量的信息,且这些信息在内存中是连续存储的。是最常用的类型,一般来说,帧缓冲中的默认取值都是此宏!

        FB_TYPE_PLANES :

          表示像素的各个颜色分量(如红色、绿色、蓝色等)被分离地存放在不同的平面(Planes)中。每个平面包含像素数据的一个或多个颜色分量,平面的个数通常等于像素的有效位数。在内存中通常是独立的。

        FB_TYPE_INTERLEAVED_PLANES:

           表示像素的各个颜色分量(如红色、绿色、蓝色等)被分离地存放在不同的平面中,但这些平面在内存中的排列方式是交错的,而不是完全独立的。

        FB_TYPE_TEXT:

           当type被设置为 FB_TYPE_TEXT时,表示帧缓冲设备当前工作在文本模式下。


        FB_TYPE_VGA_PLANES:

       用于指示帧缓冲设备当前使用的显示模式是 EGA/VGA 多层显示模式。这种模式通常用于兼容旧式的 VGA 显示设备和一些需要特定显示格式的应用程序。

        FB_TYPE_FOURCC:   

               暂不清楚是干啥的,有兴趣的可以自己查查看。

type_aux        附加类型,可以参考fb.h内的宏定义FB_AUX_XXX共有19个,数量太多不一一介绍

visual        显示的色彩模式 共有七个如下:

        FB_VISUAL_MONO01  单色显示,每一个像素由一个bit表示亮灭。

        FB_VISUAL_MONO10  与上一个相同,但亮灭的bit数值相反(即01和10的区别)

        FB_VISUAL_TRUECOLOR 真彩色,一般都是这个值

        FB_VISUAL_PSEUDOCOLOR 伪彩色模式,伪彩色模式在需要显示大量颜色但硬件资源有限的情况下更为高效。它通过使用索引值和颜色查找表来减少所需的内存带宽和存储空间。但颜色过度不如真彩色平滑。

        FB_VISUAL_DIRECTCOLOR 直接色彩模式,每个像素由红、绿、蓝三个颜色分量的索引值组成。这些索引值可能直接映射到特定的颜色范围,或者通过简单的计算(如位移和掩码操作)来解析出实际的RGB值。综合效率与质量的模式。

       FB_VISUAL_STATIC_PSEUDOCOLOR 静态伪彩色模式,在使用后,颜色的显示范围不可被软件更改。

        FB_VISUAL_FOURCC 基于V4L2 FOURCC编码的视觉模式。

xpanstep        水平方向上的PAN显示,默认为1支持,为0则不支持 PAN操作允许用户通过鼠标或键盘快捷键来平移视图,以便查看图形的不同部分。

ypanstep        垂直方向的PAN显示,同上

ywrapstep         与PAN显示类似,但当视图平移到底部时,可以从起始地址重新开始显示。(有点像贪吃蛇^_^)

line_length        一行像素所需要的字节大小,一般与色深和分辨率大小有关。

mmio_start        显存映射的物理起始地址,一般是没什么用,我用的话一般都需要mmap函数映射一下物理地址,这个用不上。

mmio_len        显存映射物理内存的长度,同上。

accel        硬件加速,一般记录有哪个设备支持。

capabilities        当配置为1时,支持FOURCC代码来配置像素数据的格式

reserved[2]        为后续功能保留的两字节。

以上就是fb_fix_screeninfo结构体的内容,是不可更改的,里面的内容都是根据用户的硬件填充的,记录的是硬件的固定信息。我们在使用帧缓冲绘制时,往往只需要关注有限的几个参数如smem_start、smem_len和line_length。

下面来看fb_var_screeninfo的内容,这里的内容是可以使用ioctl进行设置的。

xres、yres        屏幕的实际大小,即分辨率

xres_virtual、yres_virtual        虚拟屏幕的大小,按我的理解,帧缓冲一般都是渲染出一帧虚拟屏幕,再把这一帧一起显示在实际屏幕上,这两个参数一般设置为xres和yres的大小。

xoffset、yoffset        虚拟屏幕和实际屏幕的偏移(分辨率大小之差?亦或是内存的偏移?这个我弄的不是很明白,有大佬知道可以评论区告知一下)

bits_per_pixel        bpp色深,即每个像素需要多少bit,越大就代表颜色细节越多,一般来说就是取默认值,根据你屏幕来的。(插一嘴,这玩意儿的注释是 guess what    ubuntu的开发者还是挺幽默的)

grayscale        0:以彩色模式显示 1:以灰度模式显示

struct fb_bitfield red       
struct fb_bitfield green    
struct fb_bitfield blue
struct fb_bitfield transp
    

这四个结构体分别包含了,红、绿、蓝、透明度的位域信息 

nonstd        不为0时就非标准像素格式

activate        用户写入fb_var_screeninfo这个结构体的内容后,生效的时间,默认是马上生效,具体可看FB_ACTIVATE_xxx

height、width        屏幕的宽和高单位mm,默认为-1。

accel_flags        加速标志,可能与硬件加速有关,我没有深入去看。

剩下一些内容我都没有仔细去看,我需要使用的目前就这么多。

值得一提的是,xres_virtual和yres_virtual,这两个参数在支持双重缓冲的设备上,可以设置为实际分辨率的两倍大小,可以让设备在显示这一帧时,渲染下一帧画面。

ok终于看完了这两个结构体,下面开始写代码。

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

#define FBDEVICE "/dev/fb0"
void draw_back(unsigned int *pfb, unsigned int width, unsigned int height, unsigned int color);

void draw_line(unsigned int *pfb, unsigned int width, unsigned int height);

int main(void)
{
    int fd = -1;
    int ret = -1;
    unsigned int *pfb = NULL;
//定义两个结构体
    struct fb_fix_screeninfo finfo;
    struct fb_var_screeninfo vinfo;

//打开设备
    fd = open(FBDEVICE, O_RDWR);
    if (fd < 0)
    {
        perror("open");
        return -1;
    }
    printf("open %s success \n", FBDEVICE);

   //使用ioctl函数读取内容,注意中间的参数是宏定义,具体可参照fb.h
   //告诉ioctl我要读哪里的信息
    ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
    if (ret < 0)
    {
        perror("ioctl");
        return -1;
    }
    //同上
    ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
    if (ret < 0)
    {
        perror("ioctl");
        return -1;
    }
    
    //这里使用mmap把显存映射到内存里面,通过操作内存的方式绘制
    pfb = (unsigned int *)mmap(NULL, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (NULL == pfb)
    {
        perror("mmap");
        return -1;
    }
    printf("pfb :0x%x \n", *pfb);
    
    //注意 你的设备可能与我的不一样,绘制可能会报段错误
    draw_back(pfb, vinfo.xres_virtual, vinfo.yres_virtual, 0xffff0000);
    draw_line(pfb, vinfo.xres_virtual, vinfo.yres_virtual);

    close(fd);
    return 0;
}


void draw_back(unsigned int *pfb, unsigned int width, unsigned int height, unsigned int color)
{
    unsigned int x, y;
    for (y = 0; y < height; y++)
    {
        for (x = 0; x < width; x++)
        {
            *(pfb + y * width + x) = color;
        }
    }
}

void draw_line(unsigned int *pfb, unsigned int width, unsigned int height)
{
    unsigned int x, y;
    for (x = 50; x < width - 50; x++)
    {
        *(pfb + 50 * width + x) = 0xffffff00;
    }
    for (y = 50; y < height -50; y++)
    {
        *(pfb + y * width + 50) = 0xffffff00;
    }
}

代码参考:https://www.cnblogs.com/xiaojianliu/p/8473095.html

  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值