Linux显示架构的进化之路(一):从FB到X Server

目录

一.显示架构演进历程

二.Framebuffer架构

[2.1 基本工作原理](#2.1 基本工作原理)

[2.2 应用编程实例](#2.2 应用编程实例)

[2.3 优缺点](#2.3 优缺点)

[三.X Server架构](#三.X Server架构)

[3.1 基本原理](#3.1 基本原理)

[3.1.1 无GPU的平台](#3.1.1 无GPU的平台)

[3.1.2 有GPU的平台](#3.1.2 有GPU的平台)

[3.2 DDX驱动实例](#3.2 DDX驱动实例)

[3.2.1 无GPU的平台](#3.2.1 无GPU的平台)

[3.2.2 有GPU的平台](#3.2.2 有GPU的平台)

[3.3 优缺点](#3.3 优缺点)


一.显示架构演进历程

Linux显示架构大致经历了以下几个时期。这一演进历程的主要推动力在于:

1.性能需求

特别是 3D 图形应用对低延迟和高吞吐量的不懈追求。

2.功能需求

多窗口、桌面合成、视觉特效等需要更精细的图形资源管理和调度。

3.安全与稳定性需求

需要将高权限的硬件访问置于内核的严格控制之下。

二.Framebuffer架构

2.1 基本工作原理

Framebuffer,即帧缓冲区,简称FB。

帧缓冲区是一块内存,这块内存的每一个单元,都直接对应着屏幕上的一个像素。这是一种基于内存映射的直接写屏机制。

应用程序想要改变屏幕显示,只需像在白纸上写字、绘图一样,修改对应像素的数据即可。

应用程序写入数据后,并不需要通知内核。显示控制器会以固定的频率自动扫描整个帧缓冲区,并将数据转换成视频信号发送给显示器,图像便呈现出来。

显示架构如下图所示:

CPU直接在显存绘制字符或图形,如下图所示。

2.2 应用编程实例

cpp 复制代码
/*1.打开帧缓冲区设备*/
int fd = open("/dev/fb0", O_RDWR);

/*2.获取屏幕信息*/
struct fb_var_screeninfo vinfo;
ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);

/*3.内存映射帧缓冲区*/
char *fbuffer = mmap(0, vinfo.yres_virtual * vinfo.xres_virtual * 2, 
                          PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

/*4.直接写入像素*/
int x = 100, y = 100; 
int pixel_offset = y * vinfo.xres_virtual + x;
*((unsigned short*)(fbuffer + pixel_offset * 2)) = 0xF800; 

2.3 优缺点

1.优点

FB 的巨大优势在于其简单性。它提供了一个统一接口,屏蔽了不同显示硬件的差异,使得开发图形应用变得简单直接。同时,由于避免了不必要的数据拷贝,在简单场景下效率较高,非常适合早期的嵌入式系统和文本控制台。

2.缺点

三.X Server架构

3.1 基本原理

X Server 采用独特的"客户端-服务器"架构,但这与通常的网页浏览的C/S模型角色相反。

服务端​ 是 X Server​ 本身,运行在本地有显示设备的计算机上。它的职责是直接驱动显示硬件,负责基本的图形绘制。

客户端​则是应用程序,被称为 X Client。一个文本编辑器、一个浏览器,甚至桌面环境本身,都是 X Client。它们可以运行在本地,也可以运行在网络上的任何一台计算机上。

X Client 并不直接操作屏幕来显示窗口或文字。当它需要显示内容时,会通过 X 协议​ 向 X Server 发送一个"绘图请求"。

3.1.1 无GPU的平台

DDX(Device-Dependent X)驱动是用户空间的X Server组件,它通过/dev/fbx和直接内存映射(mmap)​ 的方式控制显卡。

先打开/dev/fbx,获得屏幕相关信息;然后通过mmap映射显示控制器的寄存器和显存到X Server进程空间。这样,X Server就可直接对显卡控制。

3.1.2 有GPU的平台

DDX驱动会打开GPU特定的设备文件,而不是通用的/dev/fb0。

然后直接映射GPU寄存器和显存,通过向GPU提交加速命令来利用硬件加速功能,完全绕过内核的帧缓冲区框架。

3.2 DDX驱动实例

3.2.1 无GPU的平台

cpp 复制代码
/*1.打开设备节点*/
int fbfd = open("/dev/fb0", O_RDWR);

/*2.查询显示设备信息*/	
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;

//获取可变信息(分辨率、色深等)
ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)

//获取固定信息(帧缓冲区物理地址等)  
ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)

/*3.内存映射显存*/
size_t fb_size = vinfo.yres_virtual * finfo.line_length;
char *fb_buffer = mmap(NULL, fb_size, PROT_READ | PROT_WRITE, 
                       MAP_SHARED, fbfd, 0);

/*4.绘图操作*/
//简单的绘图示例:在位置(x,y)绘制一个像素
void fbdev_draw_pixel(int x, int y, uint32_t color)
{
    // 计算像素在映射内存中的位置
    size_t offset = y * finfo.line_length + x * (vinfo.bits_per_pixel / 8);
    
    // 直接写入内存 - 立即反映在屏幕上!
    *((uint32_t*)(fb_buffer + offset)) = color;
}

3.2.2 有GPU的平台

cpp 复制代码
/*1.打开GPU专用设备节点*/
//对于早期的Intel显卡,可能是:
int gpu_fd = open("/dev/intel_gpu", O_RDWR);

//或者通过PCI设备直接访问:
int gpu_fd = open("/dev/pci/01:00.0", O_RDWR);

//现代系统可能是DRI设备:
int gpu_fd = open("/dev/dri/card0", O_RDWR);

/*2.映射GPU硬件资源*/	
volatile uint32_t *gpu_regs = mmap(...);
void *gpu_fb = mmap(...);

/*3.使用GPU加速功能*/
//启用2D加速引擎
gpu_regs[BLT_ENGINE_CONTROL] = BLT_ENGINE_ENABLE;

//设置位块传输操作
gpu_regs[BLT_SOURCE_ADDR] = source_buffer_addr;
gpu_regs[BLT_DEST_ADDR] = dest_buffer_addr;  
gpu_regs[BLT_WIDTH] = width;
gpu_regs[BLT_HEIGHT] = height;
gpu_regs[BLT_ROP] = ROP_SRC_COPY;

// 执行传输命令
gpu_regs[BLT_COMMAND] = BLT_EXECUTE;

3.3 优缺点

1.优点

2.缺点

相关推荐
炭烤毛蛋2 年前
modetest
drm·framebuffer
bjxiaxueliang2 年前
解密视频魔法:将ExternalOES纹理转化为TEXTURE_2D纹理
framebuffer·gl_texture_2d·external_oes
m0_747124532 年前
Framebuffer 介绍和应用编程
人工智能·嵌入式·imx6ull·framebuffer