【原创】Linux环境的图形系统和AMD显卡驱动编程(2)——Framebuffer、DRM、EXA和Mesa简介

1. Framebuffer

  Framebuffer驱动提供基本的显示,framebuffer驱动操作的硬件就是一个显示控制器和帧缓存(一片位于系统主存或者显卡显存)。Framebuffer驱动向应用程序提供/dev/fbx的设备接口,应用程序通过读写这个设备节点实现对显示控制器和帧缓存。

  下面这个程序显示了应用程序操作操作framebuffer节点的过程。运行这个程序,将在屏幕上方显示一个正方形(这里省略了错误检查代码)。

1 #include <stdio.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <sys/mman.h>
5 #include <sys/ioctl.h>
6 #include <linux/fb.h>
7
8 int main ()
9 {
10 int fd;
11 struct fb_var_screeninfo vinfo;
12 struct fb_fix_screeninfo finfo;
13 size_t screensize = 0;
14 int location;
15 char *fbp = NULL, *ptr;
16 int x, y, x0, y0;
17 int i,j;
18 int ret;
19
20 fd = open("/dev/fb0", O_RDWR);
21 if (fd < 0){
22 fprintf(stderr, "error open fb0\n");
23 return -1;
24 }
25 ret= ioctl(fd, FBIOGET_FSCREENINFO, &finfo ) ;
26 if (ret < 0) {
27 fprintf(stderr, "get fixed screen info error\n");
28 return -1;
29 }
30 ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
31 if (ret < 0) {
32 fprintf(stderr, "get variable screen info error\n");
33 return -1;
34 }
35 ret = ioctl(fd, FBIOPAN_DISPLAY,&vinfo);

36 if (ret < 0) {

37 fprintf(stderr, "pan display failed\n");
38 return -1;
39 }
40 screensize=vinfo.xres * vinfo.yres * vinfo.bits_per_pixel /8 ;
41 fbp = (char *)mmap(NULL, screensize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
42 if (fbp == MAP_FAILED) {
43 fprintf(stderr, "mapped error\n");
44 return -1;
45 }
46 x0 = 200;
47 y0 = 200;
48 ptr = fbp + y0 * finfo.line_length + x0 * vinfo.bits_per_pixel / 8;
49 for( i = 0; i < 100; i++){
50 char* tmp_ptr = ptr;
51 for(j = 0; j < 100; j++){
52 *tmp_ptr++ = 0;
53 *tmp_ptr++ = 255;
54 *tmp_ptr++ = 0;
55 *tmp_ptr++ = 0;
56 }
57 ptr += finfo.line_length;
58 }
59 munmap(fbp,screensize);
60 close(fd);
61 return 0;
62 }

  应用程序对framebuffer的操作主要是通过ioctl和mmap完成的。mmap将显存映射到用户空间。25行和30行分别获取当前framebuffer驱动的“固定参数”和“可变参数”,这两个参数包含了当前显示控制其的一些信息,可变参数主要是当前分辨率信息,固定参数主要是当前显存的地址。35行FBIOPAN_DISPLAY通常用于双缓存,但是这里使用还有其它意义,在后面讨论drm的framebuffer的时候还会具体讨论。41行将显存映射出来,51-59行操作这片显存,往上绘制一个左上方坐标为(200,200),边长为100的正方形。

  应用程序能够使用这些ioctl是因为内核提供了相应的接口,Linux内核设备驱动相关的书籍都会讨论framebuffer驱动,这里不讨论如何写一个framebuffer驱动。

2. DRM驱动

  前一篇博文的图4内核里面是drm驱动,注意到和图3的区别,单独的FB driver已经没有了,而是被集合到了drm驱动里面。在一些只要求进行进本显示的嵌入式系统上,依然会使用单独的framebuffer驱动,而对于内核中有3D加速的AMD、intel等驱动,内核里面和显示有关的功能已经集合到了drm驱动里面。在AMD/intel显卡+Xorg+3D这样配置的开源Linux系统上,Xorg并不使用,但是系统中仍然有/dev/fb0这样的设备节点,如果我们在桌面环境下“cat xxx >/dev/fb0”,系统不会有变化。然而如果将xorg.conf的Driver修改成“fbdev”,重启Xorg,在执行操作,能够看到有变化(关于Xorg.conf可以参考"man xorg.conf",或者查看这个页面)。或者切换到控制台终端“Ctrl+Alt+Fn”,然后运行同样的命令,就能够看到屏幕上的内容发生了变化,在这篇博文的第一节的程序有一个FBIOPAN_DISPLAY调用,这个调用会使得显卡的Crtc指向的显存地址发生变化而将当前的显示区域切换到fb0设备节点对应的区域,因此上面的程序运行即使在X桌面环境下运行,也能够看到屏幕发生了变化。这提示我们在核外X驱动正常运行的情况下,核外X驱动并不使用framebuffer驱动(实际上drm驱动注册的frambuffer设备只是给内核使用),在X启动运行后,不使用framebuffer 管理的那片内存的内容作为显示输出,而是使用了另外一片内存。

  当前的Linux系统上内核的显卡驱动称为drm驱动,在通常的linux内核发行版上,我们使用lsmod命令查看内核模块,能够看到类似下面的信息:

  radeon                933054  3

  ttm                    45600  1 radeon

  drm_kms_helper         22468  1 radeon

  drm                   162230  5 radeon,ttm,drm_kms_helper

  i2c_algo_bit            5055  2 i2c_gpio,radeon

  机器使用的是AMD的radeon显卡,上面显示了当前系统内核和显卡驱动相关的模块,drm模块是内核drm驱动的基础架构,所有drm显卡驱动都会加载这个内核模块,ttm是ttm内核管理机制,drm_kms_helper是内核模式的基础框架代码,i2c_algo_bit是显卡上操作i2c设备使用的模块,显卡上的i2c设备主要包括了connector,encoder以及pll时钟芯片。Drm内核驱动的代码在内核源码目录drivers/gpu/drm下面。加载了drm驱动后,在/dev目录下面会生成如下设备节点:

  /dev/char/226:0 -> ../dri/card0

  /dev/char/226:64 -> ../dri/controlD64

  /dev/dri/card0

  /dev/dri/controlD64

  其中/dev/dri/card0是操作gpu的接口,发送命令等操作都是通过对这个设备节点进行的。/dev/dri/controlD64是kms相关的设备节点。

  Linux下的图形驱动的主要部分是核外部分,核外部分包括了xorg exa驱动以及mesa 3d 驱动,exa是传统的2D加速框架,mesa 3d驱动则是针对3D驱动的硬件加速。由于历史原因,在Fedora 16以及更早和稍后的系统上,即使现在硬件上不包含单独的2D部件2D功能是由3D部件实现的,但是2D驱动和3D仍然是分离的。

3. EXA驱动

  早期的2D加速驱动使用的是XAA、KAA架构,但是随着composite扩展的加入,新的exa框架产生了,EXA删除掉了原来2D驱动中的三角形绘制、线绘制等一些现在没什么用处的功能,取而代之的是三个加速功能:矩形填充(Solid)、拷屏操作(Copy/Blt)和混合操作(Composite)。

  “XFree86 server 4.x Design (DRAFT)”文详细介绍xorg驱动需要提供的接口,EXA驱动通过扩展的形式添加并编译到xorg驱动中。在后续的blog文章里面将介绍exa驱动接口,并使用radeon的exa驱动来描述显卡驱动编程过程。

4. 3D驱动

  在linux环境中,我们可以通过glxinfo命令插卡3D硬件图形加速是否可用。比如在radeon显卡上glxinfo的输出包含以下内容:

  OpenGL renderer string: Gallium 0.4 on AMD CEDAR

  这里显示使用AMD CEDAR核心的显卡进行opengl 3d加速,如果硬件加速不可用,则应当是“vmware on llvmpipe”这类字眼。

  开源的OpenGL实现是mesa,mesa向上提供OpenGL接口,下层通过硬件的mesa驱动和硬件交互。GLX是X协议的扩展,用于OpenGL和X的交互(GLX规范)。在mesa源码包中包含了大量的opengl示例程序,包括OpenGL红宝书中的示例代码、调用GLUT或者GLX接口的代码、调用EGL的代码等。

图1

  图1显示了一个3D应用程序运行的过程,OpenGL绘图程序命令被用户空间的mesa驱动翻译成对应GPU的绘图命令放入命令缓冲区中,其他的如顶点信息/纹理信息/索引信息放入到相应缓冲中,mesa驱动为每个应用程序保存了当前的绘图状态,当发生3D程序切换,当前状态被保存下来,当下次调度该程序运行的时候,先恢复该程序的绘图状态到硬件上,然后继续执行命令缓存中的命令。当用户空间调用发送命令到内核的时候,内核驱动对硬件进行编程从该程序的命令缓冲区中取命令开始执行。这个过程是在dri框架下实现的,这里的所有绘制过程并不请求X,OpenGL直接将命令发送给硬件。GLX在初始化窗口,申请buffer和切换buffer的时候才会和X交互。

  图1来自文献“Graphic Engine Resource Management”,这篇文章描述了对早期的内核drm驱动做的一些改进,在这篇硕士论文“A Fair-Share Scheduler for the Graphics Processing Unit对一些问题有更清楚的描述。

时间: 2025-01-19 20:57:56

【原创】Linux环境的图形系统和AMD显卡驱动编程(2)——Framebuffer、DRM、EXA和Mesa简介的相关文章

【原创】Linux环境的图形系统和AMD显卡驱动编程(1)——Linux环境下的图形系统简介

Linux/Unix环境下最早的图形系统是Xorg图形系统,Xorg图形系统通过扩展的方式以适应显卡和桌面图形发展的需要,然而随着软硬件的发展,特别是嵌入式系统的发展,Xorg显得庞大而落后.开源社区开发开发了一些新的图形系统,比如Wayland图形系统. 由于图形系统.3D图形本身的复杂以及历史原因,Linux下的图形系统相关的源码庞大而且复杂,而且缺少学习的资料(所有源代码分析或者驱动编程的书籍都很少介绍显卡驱动).在后续一系列文章中,笔者将从对AMD硬件编程的角度出发对部分问题做一个简单的

【原创】Linux环境下的图形系统和AMD R600显卡编程(3)——AMD显卡简介

早期的显卡仅用于显示,后来显卡中加入了2D加速部件,这些部件用于做拷屏,画点,画线等操作.随着游戏.三维模拟以及科学计算可视化等需要,对3D的需求逐渐增加,早期图形绘制工作由CPU来完成,要达到真实感和实时效果,只能绘制一些简单的线框模型,上世纪80年代,斯坦福大学的Jim Clark教授率先提出用专用集成电路技术实现一个专用的3D图形处理器的设想,于1984年推出了世界上第一个通用图形工作站IRIS1400. AMD最早的显卡从R100开始,一直到R900(R600以后也使用HD xxxx作为

【原创】Linux环境下的图形系统和AMD R600显卡编程(4)——AMD显卡显存管理机制

显卡使用的内存分为两部分,一部分是显卡自带的显存称为VRAM内存,另外一部分是系统主存称为GTT内存(graphics translation table和后面的GART含义相同,都是指显卡的页表,GTT 内存可以就理解为需要建立GPU页表的显存).在嵌入式系统或者集成显卡上,显卡通常是不自带显存的,而是完全使用系统内存.通常显卡上的显存访存速度数倍于系统内存,因而许多数据如果是放在显卡自带显存上,其速度将明显高于使用系统内存的情况(比如纹理,OpenGL中分普通纹理和常驻纹理). 某些内容是必

Linux环境下的图形系统和AMD R600显卡编程(1)——Linux环境下的图形系统简介

转:https://www.cnblogs.com/shoemaker/p/linux_graphics01.html Linux/Unix环境下最早的图形系统是Xorg图形系统,Xorg图形系统通过扩展的方式以适应显卡和桌面图形发展的需要,然而随着软硬件的发展,特别是嵌入式系统的发展,Xorg显得庞大而落后.开源社区开发开发了一些新的图形系统,比如Wayland图形系统. 由于图形系统.3D图形本身的复杂以及历史原因,Linux下的图形系统相关的源码庞大而且复杂,而且缺少学习的资料(所有源代码

【原创】Linux环境下的图形系统和AMD R600显卡编程(6)——AMD显卡GPU命令格式

前面一篇blog里面描述了命令环缓冲区机制,在命令环机制下,驱动写入PM4(不知道为何会取这样一个名字)包格式的命令对显卡进行配置.这一篇blog将详细介绍命令包的格式. 当前定义了4中命令包,分别是0型/1型/2型和3型命令包,命令包由两部分组成,第一部分是命令包头,第二部分是命令包主体,命令包头为请求GPU执行的具体操作,命令主体为执行该操作需要的数据. 0型命令包 0型命令包用于写连续N个寄存器.包主体部分是依次往这些寄存器写的值.包头各个部分的意义为: 位 域名称 描述 12:0 BAS

【原创】Linux环境下的图形系统和AMD R600显卡编程(5)——AMD显卡显命令处理机制

通常通过读写设备寄存器对设备进行编程,在X86系统上,有专门的IO指令进行编程,在其他诸如MIPS.SPARC这类系统上,通过将设备的寄存器映射到内存地址空间直接使用读写内存的方式对设备进行编程. Radeon显卡提供两种方式对硬件进行编程,一种称为“推模式”(push mode)即直接写寄存器的方式,另一种称为拉模式,这篇blog讨论拉模式,这也是驱动中使用的模式. 在拉模式下,驱动使用命令流(Command Stream)的形式进行对显卡编程:驱动程序将需要对显卡进行配置的一连串命令写入命令

【原创】Linux环境下的图形系统和AMD R600显卡编程(9)——R600显卡的3D引擎和图形流水线

1. R600 3D引擎 R600核心是AMD一款非常重要的GPU核心,这个核心引入了统一处理器架构,其寄存器和指令集同以前的GPU 都完全不同,对其编程也有比较大的区别. 图1显示了R600 GPU 核心的硬件逻辑图,R600 GPU 包含并行数据处理阵列(DPP array).命令处理器.内存控制器以及其他逻辑部件,R600的命令处理器读取驱动编写命令并解析命令,R600还要将硬件产生的“软中断”发送给CPU.R600的内存控制器能够访问R600 GPU核上的所有内存(VRAM内存,或者称本

【原创】Linux环境下的图形系统和AMD R600显卡编程(8)——AMD显卡DRM驱动初始化过程

前面几个blog对DRM驱动.显卡的显存管理机制.中断机制都进行了一些描述,现在阅读AMD drm驱动的初始化过程应该会轻松许多. 下面是一AMD的开发人员编写的文章(先暂时放在这里,后续有时间再添加自己的看法). Understanding GPUs from the ground up I get asked a lot about learning how to program GPUs.  Bringing up evergreen kms support seems like a go

【原创】Linux环境下的图形系统和AMD R600显卡编程(7)——AMD显卡的软件中断

CPU上处理的中断可以分成“硬件中断”和“软件中断”两类,比如网卡产生的中断称为硬件中断,而如果是软件使用诸如"int 0x10"(X86平台上)这样的指令产生中断称为软件中断,硬件中断是异步的,其发生的时机是不可知的,但是软件中断是同步的,CPU是“确切”知道其发生的时机的. 同样的,在GPU开来,中断也可以分成“硬件中断”和“软件中断”两类,比如热插拔事件或者vblank事件都会产生“硬件中断”,这些事件在GPU看来是异步的,GPU不知道这些事情何时发生.GPU也可以使用类似CPU