Linux环境下的图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介
转:https://www.cnblogs.com/shoemaker/p/linux_graphics02.html
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 管理的那片内存的内容作为显示输出,而是使用了另外一片内存。(但是:GPU处理完成的图像数据输出到frambuffer。见:https://blog.csdn.net/esc_110/article/details/73300643)
当前的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相关的设备节点。
通常核外的驱动程序使用ioctl调用同内核进行交互,linux系统上核外对drm的ioctl进行了一层封装,即libdrm,应用程序通过libdrm调用操作硬件,关于drm的调用,这里有一些比较好的示例代码 https://github.com/dvdhrm/docs,这份代码主要调用libdrm进行模式设置,有详细的注释。
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”对一些问题有更清楚的描述。
其他参考资料:
DRM and KMS kernel modules 描述了drm驱动和kms的一些细节。
Linux环境下的图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介的更多相关文章
- 【原创】Linux环境下的图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介【转】
转自:http://www.cnblogs.com/shoemaker/p/linux_graphics02.html 1. Framebuffer Framebuffer驱动提供基本的显示,fram ...
- 【原创】Linux环境下的图形系统和AMD R600显卡编程(1)——Linux环境下的图形系统简介
Linux/Unix环境下最早的图形系统是Xorg图形系统,Xorg图形系统通过扩展的方式以适应显卡和桌面图形发展的需要,然而随着软硬件的发展,特别是嵌入式系统的发展,Xorg显得庞大而落后.开源社区 ...
- Linux环境下的图形系统和AMD R600显卡编程(1)——Linux环境下的图形系统简介
转:https://www.cnblogs.com/shoemaker/p/linux_graphics01.html Linux/Unix环境下最早的图形系统是Xorg图形系统,Xorg图形系统通过 ...
- 【原创】Linux环境下的图形系统和AMD R600显卡编程(6)——AMD显卡GPU命令格式
前面一篇blog里面描述了命令环缓冲区机制,在命令环机制下,驱动写入PM4(不知道为何会取这样一个名字)包格式的命令对显卡进行配置.这一篇blog将详细介绍命令包的格式. 当前定义了4中命令包,分别是 ...
- 【原创】Linux环境下的图形系统和AMD R600显卡编程(3)——AMD显卡简介
早期的显卡仅用于显示,后来显卡中加入了2D加速部件,这些部件用于做拷屏,画点,画线等操作.随着游戏.三维模拟以及科学计算可视化等需要,对3D的需求逐渐增加,早期图形绘制工作由CPU来完成,要达到真实感 ...
- 【原创】Linux环境下的图形系统和AMD R600显卡编程(9)——R600显卡的3D引擎和图形流水线
1. R600 3D引擎 R600核心是AMD一款非常重要的GPU核心,这个核心引入了统一处理器架构,其寄存器和指令集同以前的GPU 都完全不同,对其编程也有比较大的区别. 图1显示了R600 GPU ...
- 【原创】Linux环境下的图形系统和AMD R600显卡编程(5)——AMD显卡显命令处理机制
通常通过读写设备寄存器对设备进行编程,在X86系统上,有专门的IO指令进行编程,在其他诸如MIPS.SPARC这类系统上,通过将设备的寄存器映射到内存地址空间直接使用读写内存的方式对设备进行编程. R ...
- 【原创】Linux环境下的图形系统和AMD R600显卡编程(10)——R600显卡的3D引擎编程
3D图形处理流水线需要流经多个硬件单元才能得到最后的渲染结果,流水线上的所有的硬件单元必须被正确编程,才能得到正确的结果. 总体上看,从图形处理流水线的源头开始,需要准备好vertex和index,在 ...
- 【原创】Linux环境下的图形系统和AMD R600显卡编程(7)——AMD显卡的软件中断
CPU上处理的中断可以分成“硬件中断”和“软件中断”两类,比如网卡产生的中断称为硬件中断,而如果是软件使用诸如"int 0x10"(X86平台上)这样的指令产生中断称为软件中断,硬 ...
随机推荐
- Ultra-QuickSort - poj 2299 (归并排序+统计逆序数)
利用归并排序统计逆序数,利用归并求逆序在对子序列s1和s2在归并时(s1,s2已经排好序),若s1[i]>s2[j](逆序状况),则逆序数加上s1.length-i,因为s1中i后面的数字对于s ...
- 结果集(ResultSet)用法
结果集(ResultSet)是数据中查询结果返回的一种对象,可以说结果集是一个存储查询结果的对象,但是结果集并不仅仅具有存储的功能,他同时还具有操纵数据的功能,可能完成对数据的更新等. 结果集读取数据 ...
- python3基础知识学习记录
学习地址:http://www.runoob.com/python3/python3-tutorial.html ------------------------------ 为什么要学python: ...
- Android初体验-D3
1. UI界面布局. (即可用XML控制布局也可采用Java代码布局,不过在实际应用中是两者混合控制UI界面,为什么呢,因为XML适用于固定的不易改变的组件布局,Java程序控制常变的组件...其控制 ...
- urllib -- ProxyHandler处理器(代理设置)
import urllib.requestimport randomimport ssl proxy_list = [ {"https" : "196.61.27.58: ...
- Java格式化日期的三种方式
1)借助DateFormat类: public String toString(Date d) { SimpleDateFormat sdf = new SimpleDateFormat(“yyyy- ...
- Introduction to Mathematical Thinking - Week 9 评论答案2
根据 rubic 打分. 1. 我认为,如果说明 m, n 是自然数,所以最小值是 1 会更清楚.所以 Clarity 我给了 3 分.其他都是 4 分,所以一共是 23 分. 2. 我给出的分数 ...
- coursera 《现代操作系统》 -- 第十周 文件系统(2)
身份验证 Authentication 知道用户是谁.通过账号密码.Id 这样的识别出来. 访问控制 Permission 知道用户是谁后. 主动控制 记录用户ID和对应的访问权限 --> 记录 ...
- shell一则-按文件每行长度排序
按文件每行长度排序 awk -F: '{print length($0) " " $0}' /etc/shadow | sort -r -n | awk '{print $2} ...
- MySQL中Index Condition Pushdown(ICP)优化
在MySQL 5.6开始支持的一种根据索引进行查询的优化方式.之前的MySQL数据库版本不支持ICP,当进行索引查询是,首先根据索引来查找记录,然后在根据WHERE条件来过滤记录.在支持ICP后,My ...