本文可能需要你有一些系统架构,内核模块,Linux驱动,VFS(虚拟文件系统)子系统等背景知识;
本文不是对OpenGL图形学的介绍,而是从OS层次对图形显示架构进行的讨论;
本文主要以文字叙述为主,配以少量框图解释。后期如果有机会,会增加一些图片进行解释。
一、从图形学角度来看Linux内核
实模式下编程,我们了解到:在低地址内存空间,有一段内存区域可以向显示屏输出,即FB架构(Frame Buffer)。该显示架构一般用作实模式下的字符输出——字符模式。
二、聊聊显卡(集显与独显),从总线架构来看
不管是内存,还是显卡,作为计算机必不可少的模块,其都是与CPU的PCI总线直接相连(挂载于PCI总线上)。
PCI发展到现阶段的扩展版本:PCIe,下文以PCIe进行叙述。
既然显卡位于CPU PCIe总线上,那就是说设备可以存在地址映射,这样内核级代码便可以对其进行操作。同时,也由于显卡本身不属于CPU内部架构,所以不可能为其引入单独的指令集。这与AVX,MMX,SSE等CPU内部指令集是不同的,与CPU对内存进行MOV等指令操作也是不同的。当然,显卡的地位还没到内存这么高,虽然同为PCIe总线上的设备。
字符模式的初始化是加电自检阶段由BIOS基础输入输出系统完成,包含了内存地址的映射。在硬件微电路层面,BIOS可能会对内存地址空间进行重排等操作。
Linux要想通过PCIe访问显卡,那便需要PCIe总线的驱动。
引入思考:PCIe总线的初始化过程是怎样的?
认识PCIe总线的地位:
三、继续聊聊显卡,从内核模块角度分析
众说周知,要想访问显卡,除了上述所说的PCIe总线驱动,还需要显卡厂商提供的驱动。无论Windows还是Linux,虽然这两者驱动完全不同。
我们来分析一下Linux下的显卡驱动:
对于集成显卡,通过lspci命令,一般能够看到一个intel的显卡;
对于独立显卡,通过lsmod命令,一般可以看到nvidia或radeon显卡驱动模块。
lspci: 用于查找PCIe总线上的设备;lsmod: 用于查看内核模块中的驱动。
DRM(内核驱动模块)——对显卡硬件的一层抽象,或者说通用显卡访问层。通过DRM驱动,系统可使用通用接口访问各种不同类型的显卡。当然,lsmod | grep nvidia有时候也能找到英伟达独立的驱动(为啥被Linus喷?固执自家那套)。同时,也有nivdia_drm跟DRM兼容的驱动提供。
四、聊聊用户态进程对显示图形的绘制
我们知道用户态进程本身是不能直接操作硬件的,Linux哲学告诉我们 “万物皆文件”。那么想让用户态进程输出图形到显示屏,那么内核必然要在VFS中提供设备文件供用户态进程使用。一般而言,该设备文件在内核模块的实现,就落在DRM驱动头上了。
我们可能听说绘制显示屏其实就是向显存中写入图像数据,而内存与显存是存在映射关系的,那么我们在一段内存中写入数据,其实就是在屏幕上绘制图像。道听途说?但是有道理的!在这里,DRM就完成了这些环境设置的准备工作。这里,我们暂且不考虑性能问题,即内存段被copy了多少次?以及怎样使用copy on write思想来优化它?
Linux设备文件说明:
/dev/dri/card0 这就是DRM内核驱动模块实现并提供给用户态进程的设备文件接口了!
/dev/fb0 FrameBuffer架构的文件,也是DRM提供,直接放在dev下,可能是为了兼容老的方案。
关于Linux下的图形化架构,暂且就先讲到这里。该部分内容比较偏底层,应用层也就是用户态进程,还会进一步接管并控制这些底层的图形化接口。这部分其实就是X-window啦!我之前写过一篇就是关于这个的,有兴趣的话可以看一下!