Linux图形子系统

基本概念

GUI、窗口系统、窗口管理器、GUI工具集、桌面环境、3D渲染、硬件加速

窗口系统

窗口系统,是GUI的一种(也是当前计算机设备、智能设备广泛使用的一种),以WIMP (windows、icons、menus、pointer) 的形式,提供人机交互接口。Linux系统中有很多窗口系统的实现,如X Window System、Wayland、Android SurfaceFlinger等。
思路如下:

  • 1)一般都使用client-server架构,server(称作display server,或者windows server、compositor等等)管理所有输入设备,以及用于输出的显示设备。
  • 2)应用程序作为display server的一个client,在自己窗口(window)中运行,并绘制自己的GUI。
  • 3-1)client的绘图请求,都会提交给display server,display server响应并处理这些请求,以一定的规则混合、叠加,最终在有限的输出资源上(屏幕),显示多个应用程序的GUI。
  • 3-2)display server和自己的client之间,通过某种类型的通信协议交互,该通信协议通常称作display server protocol。
  • 4)display server protocol可以是基于网络的,甚至是网络透明的(network transparent),如X Window System所使用的。也可以是其它类型的,如Android SurfaceFlinger所使用的binder。

X Window System

  • 2)从2004年的时候,XFree86不再遵从GPL许可证发行,导致许多发行套件不再使用XFree86,转而使用Xorg,再加上Xorg在X维护工作上又趋于活跃,现在Xorg由成为X的代名词(具体可参考“http://www.x.org/”)。

  • 3)X设计之初,制定了很多原则,其中一条----"It is as important to decide what a system is not as to decide what it is”,决定了X的“性格”,即:X只提供实现GUI环境的基本框架,如定义protocol、在显示设备上绘制基本的图形单元(点、线、面等等)、和鼠标键盘等输入设备交互、等等。它并没有实现UI设计所需的button、menu、window title-bar styles等元素,而是由第三方的应用程序提供。这就是Unix的哲学:只做我应该做、必须做的事情。这就是这么多年来,X能保持稳定的原因。也是Linux OS界面百花齐放(不统一)的原因,各有利弊吧,后续文章会展开讨论。

  • 4)X包括X server和X client,它们之间通过X protocol通信。

  • 5)X server接收X clients的显示请求,并输出到显示设备上,同时,会把输入设备的输入事件,转递给相应的X client。X server一般以daemon进程的形式存在。

  • 6)X protocol是网络透明(network-transparently)的,也就是说,server和client可以位于同一台机器上的同一个操作系统中,也可以位于不同机器上的不同操作系统中(因此X是跨平台的)。这为远端GUI登录提供了便利,如上面图片所示的运行于remote computer 的terminal emulator,但它却可以被user computer的鼠标键盘控制,以及可以输出到user computer的显示器上。
    注4:这种情况下,user computer充当server的角色,remote computer是client,有点别扭,需要仔细品味一下(管理输入设备和显示设备的是server)。

  • 7)X将protocol封装为命令原语(X command primitives),以库的形式(xlib或者xcb)向client提供接口。X client(即应用程序)利用这些API,可以向X server发起2D(或3D,通过GLX等扩展,后面会介绍)的绘图请求。

Linux图形软件层次

linux系统中图形有关的软件层次,具体如下:

虽然图形子系统的层次比较多,但不同的人可能关注的内容不太一样。例如对Linux系统工程师(驱动&中间件)而言,比较关注hardware、kernel和display server这三个层次。而对Application工程师来说,可能更比较关心GUI Toolkits。本文以及后续display subsystem的文章,主要以Linux系统工程师的视角,focus在hardware、kernel和display server(可能包括windows manager)上面。

以X window为例, 将hardware、kernel和display server展开如下:

  • 1)3D-game engine、Applications和Toolkits,应用软件,其中3D-game engine是3D application的一个特例。
  • 2)Display Server
    图片给出了两个display server:Wayland compositor和X-Server(X.Org)。X-Server是linux系统在PC时代使用比较广泛的display server,而Wayland compositor则是新设计的,计划在移动时代取代X-Server的一个新的display server。
  • 3)libX/libXCB和libwayland-client
    display server提供给Application(或者GUI Toolkits)的、访问server所提供功能的API。libX/libXCB对应X-server,libwayland-client对已Wayland compositor。
  • 4)libGL
    libGL是openGL接口的实现,3D application(如这里的3D-game engine)可以直接调用libGL进行3D渲染。
    libGL可以是各种不同类型的openGL实现,如openGL(for PC场景)、openGL|ES(for嵌入式场景)、openVG(for Flash、SVG矢量图)。
    libGL的实现,既可以是基于软件的,也可以是基于硬件的。其中Mesa 3D是OpenGL的一个开源本的实现,支持3D硬件加速。
  • 5)libDRM和kernel DRM
    DRI(Direct Render Infrastructure)的kernel实现,及其library。X-server或者Mesa 3D,可以通过DRI的接口,直接访问底层的图形设备(如GPU等)。
  • 6)KMS(Kernel Mode Set)
    一个用于控制显示设备属性的内核driver,如显示分辨率等。直接由X-server控制。

显示框架

1)Wayland client+Wayland compositor+Mesa+DRM+KMS,因为它们之中,除了Mesa之外,其它的都是linux系统中显示有关的比较前沿的技术。当然,最重要的,是比较适合移动端的技术。

2)通过单独的一篇文章,更详细的分析Wayland+Mesa+DRM+KMS的软件框架,着重分析图像送显、3D渲染、Direct render的过程,以此总结出DRM的功能和工作流程。

3)之后,把重心拉回kernel部分,主要包括DRM和KMS,当然,也会顺带介绍framebuffer。

4)kernel部分分析完毕后,回到Wayland,主要关心它的功能、使用方式等等。

DRI工作流

由于很多高性能的图形设备,要求相应的应用程序直接访问硬件,实现性能最优。结果就是为3D rendering另起炉灶,给出一个直接访问硬件的框架,DRI就应运而生了,如下:

软件架构

linux图形系统设计思路的转变:
从以前的:X serve是宇宙的中心,其它的接口都要和我对话。
转变为:Linux kernel及其组件为中心,X server(如Wayland compositor等)只是角落里的一员,可有可无。

基于DRI的linux图形系统如下:

该框架以基于Wayland的Windowing system为例,描述了linux graphic系统在DRI框架下,通过两条路径(DRM和KMS),分别实现Rendering和送显两个显示步骤。从应用的角度,显示流程是:

1)Application(如3D game)根据用户动作,需要重绘界面,此时它会通过OpenGL|ES、EGL等接口,将一系列的绘图请求,提交给GPU。

  • a)OpenGL|ES、EGL的实现,可以有多种形式,这里以Mesa 3D为例,所有的3D rendering请求,都会经过该软件库,它会根据实际情况,通过硬件或者软件的方式,响应Application的rendering请求。
  • b)当系统存在基于DRI的硬件rendering机制时,Mesa 3D会通过libGL-meas-DRI,调用DRI提供的rendering功能。
  • c)libGL-meas-DRI会调用libdrm,libdrm会通过ioctl调用kernel态的DRI驱动,这里称作DRM(Direct Rendering Module)。
  • d)kernel的DRM模块,最终通过GPU完成rendering动作。

2)GPU绘制完成后,将rendering的结果返回给Application。rendering的结果是以image buffer的形式返回给应用程序。

3)Application将这些绘制完成的图像buffer(可能不知一个)送给Wayland compositor,Wayland compositor会控制硬件,将buffer显示到屏幕上。
Wayland compositor会搜集系统Applications送来的所有image buffers,并处理buffer在屏幕上的坐标、叠加方式后,直接通过ioctl,交给kernel KMS(kernel mode setting)模块,该模块会控制显示控制器将图像显示到具体的显示设备上。

DRM和KMS

DRM是Direct Rendering Module的缩写,是DRI框架在kernel中的实现,负责管理GPU(或显卡,graphics card)及相应的graphics memory,主要功能有二:

1)统一管理、调度多个应用程序向显卡发送的命令请求,可以类比为管理CPU资源的进程管理(process management)模块。

2)统一管理显示有关的memory(memory可以是GPU专用的,也可以是system ram划给GPU的,后一种方法在嵌入式系统比较常用),该功能由GEM(Graphics Execution Manager)模块实现,主要包括:

a) 允许用户空间程序创建、管理、销毁video memory对象(称作“"GEM objects”,以handle为句柄)。
b)允许不同用户空间程序共享同一个"GEM objects”(需要将不唯一的handle转换为同一个driver唯一的GEM name,后续使用dma buf)。
c)处理CPU和GPU之间内存一致性的问题。
d)video memory都在kernel管理,便于给到display controller进行送显(Application只需要把句柄通过Wayland Compositor递给kernel即可,kernel会自行获取memory及其内容)。

KMS是Kernel Mode Setting的缩写,也称作Atomic KMS,它是一个在linux 4.2版本的kernel上,才最终定性的技术。从字面意义上理解,它要实现的功能比较简单,即:显示模式(display mode)的设置,包括屏幕分辨率(resolution)、颜色深的(color depth)、屏幕刷新率(refresh rate)等等。一般来说,是通过控制display controller的来实现上述功能的。

也许大家会有疑问:这些功能和DRI有什么关系?说实话,关系不大,之所以要在DRI框架里面提及KMS,完全是历史原因,导致KMS的代码,放到DRM中实现了。目前的kernel版本(如4.2之后),KMS和DRM基本上没有什么逻辑耦合(除了代码位于相同目录,以及通过相同的设备节点提供ioctl之外),可以当做独立模块看待。

继续上面的话题,只是简单的display mode设置的话,代码实现不复杂吧?还真不一定!相反,KMS有关的技术背景、软件实现等,是相当复杂的,因此也就不能三言两语说得清,我会在单独的文章中重点分析KMS。

DRM in kernel