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

转:https://www.cnblogs.com/shoemaker/p/linux_graphics01.html

Linux/Unix环境下最早的图形系统是Xorg图形系统,Xorg图形系统通过扩展的方式以适应显卡和桌面图形发展的需要,然而随着软硬件的发展,特别是嵌入式系统的发展,Xorg显得庞大而落后。开源社区开发开发了一些新的图形系统,比如Wayland图形系统。

由于图形系统、3D图形本身的复杂以及历史原因,Linux下的图形系统相关的源码庞大而且复杂,而且缺少学习的资料(所有源代码分析或者驱动编程的书籍都很少介绍显卡驱动)。在后续一系列文章中,笔者将从对AMD硬件编程的角度出发对部分问题做一个简单的介绍,当然,这种介绍是很初级的,旨在希望能够对初学着有所帮助。

内核DRM、Xorg以及Mesa三部分加起来的代码和整个Linux内核的体量是差不多大的。而且现代的显卡上的GPU的复杂程度在一定程度上可以和CPU相聘美,从程序员的角度看,操作系统(CPU的驱动)包含的许多功能在GPU驱动上都能够找到。比如,GPU有自己的指令系统,着色器程序(GLSL、HLSL、Cg这类着色语言)需要经过编译成GPU的指令集,然后才能够在GPU上运行,符合着色语言规范的3D驱动都包含一个编译器。3D应用程序需要使用大量内存,GPU在进行运算的时候需要访问这些内存,GPU在访问这些内存的时候也使用一套和CPU页表一样的机制。另外,在中断系统上,GPU和CPU也有相似之处。后面的一些内容将会陆续对这些问题做一个简单的介绍。

传统上认为Linux是一个宏内核,设备驱动大部分都是包含在内核里面的,因此可以看到内核代码最庞大的部分是drivers目录,如果从kernel.org上面下载一个内核源码,直接编译,编译的时间大部分都耗在编译设备驱动上。

微内核的操作系统,设备驱动不是内核的部分。这里不讨论微内核和宏内核的区别或者各自的优缺点。但是出于调试方便以及其他一些原因,Linux操作系统上面的一些驱动是放在核外的。一个主要的类别就是打印机、扫描仪这类设备,当前的打印机扫描仪通常都是通过USB 接口连接到计算机上的,对于这些设备的Linux驱动,除了USB核心部分在内核,这些打印机扫描仪本身的驱动都是在核外的。Linux上面的打印机使用CUPS系统,CUPS运行在核外,其驱动是按照CUPS的接口来开发的。Linux上面的扫描仪使用的是运行在核外的sane系统,其驱动是以动态链接库的形式存在的。另外一类核外的驱动是图形系统的驱动,由于图形系统、显卡本身比较复杂,而且由于一些历史原因,图形系统的驱动在核内核外都有,并且显卡驱动最主要的部分在核外。

在wiki词条“Free and open-source graphics device driver”的最新页面上,对linux环境下的图形系统演变过程有一个很好的图解,这里直接使用这个页面的图进行描述 http://en.wikipedia.org/wiki/Free_and_open-source_graphics_device_driver

显卡最早只有基本的显示功能,可以成为显示控制器(Display Controller)或者帧缓冲设备,对于这样的显示控制器,当前的Linux内核对其的支持表现为framebuffer驱动,Xorg部分对其的支持是一个名为fbdev的驱动。

图1

其后显卡上逐渐加上了2D加速部件,这种情况下面的驱动如上图显示。这个情况下的架构还是比较简单的。

图2

随着3D图形显示和运算的需要,带有图形运算功能的显卡出现,这个时候需要有专门的3D驱动来处理3D,于是出现了上图的GLX driver,这里注意到X server依然处在一个中心节点的位置,无论是X11程序还是3D OpenGL程序,都要通过X server才能到底层。同时注意到到现在为止X的2D driver和GLX driver都是直接调用到硬件,而没有通过内核调用。在2.6版本的内核的系统上,依然能看到X 2D driver中有访问硬件有MMIO和CP两套代码,MMIO就是这里的情况,显卡寄存器直接暴露给核外的2D driver(和GLX driver,目前已经不存在这个了)。

这种情况下的结构仍然是比较简单的,然而这种情况有一个很大的问题,读过X server代码的(或者参考这篇文章“X Window System Internals”http://xwindow.angelfire.com/)应该知道,X server是单线程的(关于多线程X server,可以google到一些邮件讨论记录),main函数完成系统初始化之后就进入了一个循环,等待客户端程序的连入,等一个客户端程序发送完数据之后其他的客户端才能连上来,OpenGL客户端程序每次要请求硬件都必须先经过X server,然后由X server“代表”OpenGL程序进入硬件,对于场景稍微复杂的3D应用程序来说,这样频繁的和X server交互是难以保证3D渲染的实时性的。

鉴于上面的问题,引入了DRI机制,在这个机制下面,OpenGL程序对硬件的请求不再经过X server,而是自己直接和硬件交互。整个过程是这样的:在绘图之前,OpenGL程序向内核申请到一片渲染目标并告诉X server,然后OpenGL程序不经过X server而直接调用进内核请求硬件进行渲染操作,并将结果渲染到申请到的渲染目标中,渲染结束后,OpenGL程序通知X server该渲染目标发生了变化,对应的屏幕上的窗口区域需要进行更新,X server收到这个通知后,进行一次重新的窗口混合工作(当前代码是EXA的Composite功能提供的)。这个时候的情况如下图示,GLX driver被DRI driver取代,和Dri driver交互的不再是X server而直接是OpenGL程序。另外DRI(原来是GLX)不直接操作硬件,而是通过内核drm驱动操作硬件,drm提供硬件访问通道和访问机制。在当前的系统上,2D driver以EXA 2D加速驱动的形式存在于Xorg里面,DRI driver则在Mesa中。

图3

然后又添加了对远程3D client的支持AIGLX,这部分的功能和原来的Utah GLX有类似之处。AIGLX可以参考wiki页面(http://en.wikipedia.org/wiki/AIGLX)。

图4

X server通过不断扩展形成了现在的样子,显得庞大而且复杂,有些工作是不必要的。开源社区提出了更为简洁的wayland图形系统,在“揭开Wayland的面纱(一)(二)”两篇文章里面对wayland做了说明,读者可以点击下面的地址:

http://www.ibentu.org/2010/11/06/introduce-to-wayland-01.html

http://www.ibentu.org/2010/11/06/introduce-to-wayland-01.html

图5

在这两篇文章里面描述了这么一个场景:在一个图形程序上点击某个按钮。在X图形系统下,X的evdev驱动捕获到这个信息,X被告知有应用程序需要进行渲染,然后X server查询到需要渲染的窗口,然后将“鼠标点击”这个事件通知给需要渲染的窗口对应的X程序,X程序接收到通知后再告诉X server“如何进行渲染”,X server接收到“如何渲染”的消息后进行渲染(2D情况下X/EXA自己完成,3D情况下无需先通知X server,使用DRI完成绘制并由应用程序告知X渲染已经完成),完成通知X的“composite”扩展进行混合,X的composite扩展接到混合请求后告知X server混合已经完成,这里面X server和X client以及X server和X composite之间都有双向的通信,这两部分是比较耗时的,而且由于X server通知X composite之前还需要进行窗口的重叠判断、被覆盖窗口的剪载计算等——然而这些是X composite不需要的,因此会有一些额外的时间消耗。

在Wayland情况下,server主要进行composite,应用程序全部使用DRI直接渲染机制,完成后通知Server(composite)进行混合,结构上非常简单而且高效。

另外对窗口的请求也发生了变化,在X DRI下,X11和3D程序需要向X server请求窗口,那个时候X server进行的加速操作必须依赖单独的EXA驱动(无法直接调用OpenGL加速),后来的mesa做了一些修改,在wayland环境下,Application直接通过EGL、GLES driver向内核drm请求绘图窗口,而这里的composite可以直接调用OpenGLES进行加速,而无需单独有2D加速驱动。

还注意到,内核里面有一个KMS,全称是kernel mode setting(内核模式设置,设置显示分辨率之类的),前面曾经提到过,早期的显卡寄存器是直接暴漏给核外驱动的,直到现在的EXA内核代码里面仍然有MMIO和CP两种操作方式,早期X进行模式设置的时候直接写寄存器进行操作,后来内核引入了KMS(在wayland之前就已经有了),于是核外驱动可以通过调用KMS接口进行模式操作而不需要了解硬件细节。

上面提到了composite,X的composite的操作如下图示:

图6

过去的X11 client直接在显示区域上,现在X11 client窗口在off-screen显存上,compositor从这些显存上取出内容并最终混合到显示区域上去。X里面和composite操作相关的扩展有damage、render、composite,这三者描述参考以下资料:

http://cgit.freedesktop.org/xorg/proto/compositeproto/plain/compositeproto.txt

http://cgit.freedesktop.org/xorg/proto/damageproto/plain/damageproto.txt

http://cgit.freedesktop.org/xorg/proto/renderproto/plain/renderproto.txt

关于X composite的引入过程读者可以参考以下资料:

Keith Packard. Design and Implementation of the X Rendering Extension

Matthieu Herrb, Matthias Hopf. New Evolutions in the X Window System

Andy Ritger. Using the Existing XFree86/X.Org Loadable Driver Framework to Achieve a Composited X Desktop

当前的Linux环境上的图形系统架构如下图示:

图7

这里的部分内容在前面描述过了,需要注意的是X server的EXA驱动部分出现了glamor,glamor直接调用到了mesa里面,过去EXA驱动是单独的驱动,通过drm调用操作硬件,而由于mesa的改变,X可以和wayland composite一样直接调用Mesa的接口。

后面的描述将针对Fedora 16操作系统,Fedora 16系统和现在最新的系统(图7)有一定的区别,后面的一些问题的讨论主要使用图4。在后续blog中,将先对Fedora的图形系统内核、X、Mesa这个层次的部分进行一个简单的描述,然后开始介绍驱动对AMD显卡硬件部分模块(功能)的编程。

其他参考资料:

Inside Linux graphics 是intel的开发人员编写的一份介绍图形架构的文档。

Linux Graphics Drivers: an Introduction 是开源社区的开发人员写的一份文档,对Linux图形系统的各个方面都有一些介绍。

A deeper look into GPUs and the Linux Graphics Stack 这一份ppt对图形系统架构有比较深入的探讨。

Graphics Card Interfaces 这篇博文对图形架构的部分细节有一些探讨。

精通嵌入式Linux编程:构建自己的GUI环境 这本书描述了如何在framebuffer上构建一个完整的图形系统,其中的许多概念和原理在X图形系统中也能够看到。

原文地址:https://www.cnblogs.com/newjiang/p/9590809.html

时间: 2024-10-06 09:58:33

Linux环境下的图形系统和AMD R600显卡编程(1)——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显卡编程(3)——AMD显卡简介

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

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

3D图形处理流水线需要流经多个硬件单元才能得到最后的渲染结果,流水线上的所有的硬件单元必须被正确编程,才能得到正确的结果. 总体上看,从图形处理流水线的源头开始,需要准备好vertex和index,在立即模式下,index可以直接编程在命令中,通过配置寄存器告诉GPU vertex buffer的位置,在启动GPU流水线之前,还需要将vertex shader程序和pixel shader程序加载到vram 中,并通过配置寄存器告示GPU shader程序的位置,在vertex shader和p

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

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

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

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

【原创】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显卡编程(11)——R600指令集

1 低级着色语言tgsi OpenGL程序使用GLSL语言对可编程图形处理器进行编程,GLSL语言(以下高级着色语言就是指GLSL)是语法类似C的高级语言,在GLSL规范中,GLSL语言被先翻译成教低级的类汇编语言,然后被翻译成硬件特定的指令集.OpenGL体系管理委员会于2002年6月和2002年9月分别通过了两个官方扩展:ARB_VERTEX_PROGRAM与ARB_FRAGMENT_PROGRAM来统一对低级着色语言的支持,GLSL语言被编译成针对这两个扩展的低级着色语言(因此这两个扩展可