【zz】Linux 图形现状

http://blog.chinaunix.net/u/30686/showart.php?id=1945965

在淡出 Xgl 方面的工作之后,我仍收到大量 email 并阅读许多帖子。我的结论是大多数人并没有真正理解 linux 图形方面正在发生的事情。人们无法看清整体的图景,这是可以理解的。图形是一个庞杂的领域,包含着众多软件组件和相互竞争的开发小组。作为一种尝试, 我写了这篇文章,来解释所有这些部分是如何组织到一起的。

俱往矣

今年是 X server 的二十一岁生日。脱胎于 Athena 项目,自 1984 年发端以来,过去的那些年中,它很好地满足了 Unix 社团的需要。 X 已经被广泛应用,推动着今天的大多数 Linux 桌面。这篇 Wikipedia 文章2提供了更多详细资料,除了两项开源的主要 X 创新,它们允许提供跨平台支持和网络通透性。

然而,自 X 着手设计,20 年时光匆匆流逝,视频硬件今非昔比了。如果瞥一下一块现代视频芯片的架构图,你会注意到一个小小的标记着 2D 的区块。那是由于芯片的 90% 专注于 3D 管线。你正好为那些 3D 硬件付了费,因此如果桌面能利用它那不是很棒吗。很多人并未意识到 3D 硬件也可用于绘制 2D 桌面。看看你的屏幕,它是一块平平的 2D 平面,对不对?任何由 3D 硬件生成的图画最终都要显示在平的 2D 屏幕上。此一事实应能让你认识到,通过适当地编程,3D 硬件可以绘制 2D 桌面。

图形供应商

多年以前图形芯片供应商乐于为他们的硬件公开数据表和编程信息。但是随着专利库的增大,对专利侵权的恐惧也增大了。现在图 形芯片供应商将关于芯片的全部信息秘而不宣,作为使专利持有人更难搜寻侵权行为的一种手段。至少这是供应商给出的隐藏编程规范的理由。并且他们也宣称隐藏 编程规范可使竞争对手更难对他们的芯片做反相工程,但我对此同样持怀疑态度。所有这些隐藏规范使为这些芯片编写开源设备驱动异常困难。作为替代方案,我们 被迫依赖供应商来为最新的硬件提供驱动程序。如果你尚未留意,请注意图形供应商的确仅仅关心 MS Windows 因此他们只为 Linux 提供最低程度的驱动支持。也有例外。Intel 为他们的部分芯片提供开源驱动。Nvidia/ATI 提供专有驱动,但是落后于 Windows 版本。总的后果是一批非常参差不齐的驱动,品质从良好到完全空白。

桌面选择

其它的桌面选择, WindowsMac,都拥有 GPU 加速的桌面。它们明显地、眼见地比他们的前辈要好。某些情况下这些新的带加速的桌面的绘制速度能够比旧的模型快过一百倍。在未来的某个时候,图形芯片供应商会移除标记为 2D 的那个小点,仅给我们留下 3D 硬件。Microsoft 和 Apple 看起来已经得到信儿说 3D 是未来的方向并开始进行转换。另一方面。几个 X 开发者曾告诉我停止谈论竞争的图景。他们说他们想做的是让 X 更好。尽管 X 开发者可能无动于衷,我确信当由于缺乏竞争力的 GUI 而开始丧失份额的时候,Redhat 和 Novell 的经理们不会赞同此一观点。

在桌面上使用 3D 并不只是为了制造更华丽的视觉效果3。有大量利用 3D 能力生成的效果只是虚饰,但仍有些真正的理由运用 3D。简单来说 3D 快过 2D,没有人动手使他们的 2D 功能更快,所有的硅工程师都转向了 3D 。你能够完成快速、任意的图像处理,例如色彩空间转换,拉伸/卷曲,等等。我曾见过某些消耗主 CPU 几秒钟才完成一帧的超级复杂的过滤操作在 shader 硬件上以实时达成。支持任意色彩映射的不同的 Windows 色深(同时支持 8、16、24 位窗口)。为项目管理者提供极快的屏幕翻转/旋转,为视力不良者提供全屏缩放,等等。分辨率无关性允许对象以任意分辨率/尺寸渲染,当显示到屏幕上的时候再降低/提高取样精度。更多有意思的应用在后面讨论窗口化的小节里阐述。

当前的 X.org 服务器

X.org 即将发布 X11R74。这个发布的主要特性是 X 源代码库的模块化。尽管对大多数用户并无意义,模块化将使在 X 源代码上工作容易得多。模块化之前 X 源代码树包含约 16M 行代码,全部作为一个单独的项目构建。模块化之后,代码树将分解为一打左右的独立部分,使项目的构建和理解容易得多。

X,作为操作系统

X 究竟是一个应用程序还是一个操作系统?在这里有一份优秀的参考文献帮助我们理解一个 X server 是如何组织到一起的。尽管写成已有 8 年之久,大多数内容仍然切题。如果你不知道何谓 DIX、mi、DDX、CFB 什么的,最好先读读它。大概在 X11R6.3 那会儿 Xfree86 分裂了,X 服务器的设计变得极度跨平台。X 面向的众多操作系统对硬件侦测这类事情提供不同程度的支持。为了解决此类问题,X 添加了代码侦测 PCI 总线来搜寻硬件,代码搜寻视频 ROM 并运行它们来重置硬件,搜寻鼠标和键盘并提供驱动,管理多个 VGA 设备的问题,最后甚至提供它自己的模块加载器。这一步让 X 开始模糊了它是应用程序还是操作系统的界线。虽然某些操作环境的确需要这种类 OS 支持,实现这些特性来提供同样服务的操作系统,比如 Linux, 终于落到 X 和 OS 之间互相冲突的境地。当然操作系统是一个移动的标靶,十年前恰当的决策今天看来可能已经不合时宜了。

Linux 内核提供在 BSD 和某些其它平台上并不存在的子系统,比如 PCI 和 framebuffer。出于对跨平台支持的兴趣,X 服务器内建了和这些子系统平行的实现。在过去对此确有需求但在当前 Linux 系统上这导致两块不同的软件都试图控制同一个硬件。Linux 具有多个非 X 的视频硬件使用者,它们与 X 交互的唯一位置就是内核。内核提供了很多机制来协调这些使用者;反正就是 PCI 子系统,输入驱动,热拔插检测,设备驱动这档子事。为了和 Linux 一致,最佳方案是使用内核提供的特性,仅仅在其它平台上运行这些重复的库。Fbdev 和 XAA 驱动是冗余驱动的主要例子。

Linux 有一个优秀的热拔插系统,图形系统真的有必要开始利用它。显示屏可以从多个来源上热拔插。有一个传统的热拔插来源;有些人将新的显示卡插入热拔插背板。然 而存在其它非传统的途径来获得一次热拔插。另一位用户可能正在使用你要加到你的屏幕组的显示屏,当他注销的时候你就会获得一次热拔插。你可以将一台外部监 视器连接到笔记本电脑上,从而生成一次热拔插。你可以以无线方式通过 DMXChromium 这类东西连接到显示墙。USB 也是很多热拔插的来源。用户能够热拔插鼠标、手写板、键盘、音频设备、甚至图形适配器。既然不和内核的热拔插系统通信,当前 X 服务器不能处理这些情形中的任何一种。

标准的 Linux 桌面使用 rooted X。Rooted X 指的是 X 控制最上级桌面的绘制,窗口则处于它之上。 Cygwin/X,Directfb 和 Apple Darwin 都是用 rootless X。这些环境拥有另一套窗口系统负责显示。这些宿主窗口系统绘制主桌面并实现它们自己的窗口 API。通过运行在 rootless 模式,X 能够象这样被整合到一个宿主窗口系统中。在 rootless 模式下应用程序窗口绘制到系统内存中的缓冲区。在适当的时候 X 窗口和宿主窗口系统同步,于是它们的内容被显示出来了。Rootless X 也提供协议在两个环境当中传递鼠标和键盘事件。

X Render

现在讲到 X Render 扩展。Keith P 于公元 2000 年宣称现存的 X 服务器无法有效地绘制清晰的、反锯齿的文本,起而提出 X Render 扩展来解决此问题。X Render 是核心 X 特性,允许漂亮的字体和 Cairo 这类事情在 X 服务器上实现。X Render 给 X 服务器添加了 Porter-Duff 操作5。这些操作允许图面以不同的方式合并。它们与 OpenGL 纹理和纹理操作的概念非常相似,但仅仅是相似而非完全一致。

XAA

XAA,既 X 加速体系结构,是在 XFree86 4.0 中引入的。为达成跨平台可迁移性,XAA 没有利用内核设备驱动,而在用户空间实现了 2D 视频驱动。用户空间驱动的确可行,然而既然不存在基于内核的驱动,Linux 内核就无法追踪 X 对硬件作了些什么。直到你的系统引导完毕,X 都未开始运行。你应该希望启动过程中在启动 X 出麻烦的情况下仍有显示,不是吗?Linux 下的启动显示通过文本模式(控制台)驱动实现,最常见的是 VGAcon。由此 Linux 下你困于两套设备驱动, X 和控制台的,都在试图控制同一块硬件。XAA、控制台和虚拟终端(Virtual Terminal)这类 Linux 内核功能的组合会导致大量的冲突,不过容后细谈。

EXA

EXA 对现存 2D XAA 驱动的替代允许当前的服务器模型能工作更长一点。它通过提供远为高级的驱动和内存管理 API 来加速 X Redner 扩展。起初 EXA 定位为针对包括旧硬件在内的所有硬件的方案。但这并未成为现实。如果老旧的硬件缺少加速渲染核心所需的 alpha 混合硬件,你基本上就无能为力了,虽然EXA 有可能通过较好地管理显存帮助增强这些芯片的性能。所以归根结底硬件 EXA 相当程度上工作于现存OpenGL 驱动同样的硬件。Nv 和 i128 这样的例外也是有的,这些硬件具有 3D 能力却不存在 OpenGL 驱动。可以确定的是 EXA 会不断扩张来探求更多芯片中的 3D 能力。EXA 牌创可贴能顶一阵子,但非长远之计。必须牢记的是 EXA/render 仍然仅是庞大的 Mesa OpenGL API 的子集,而随着时间的推移我们总会寻求越来越多的特性。

Cairo6

Cairo 的目标是成为一套高品质的、同时适用于打印输出和屏幕显示的 2D 绘制 API。它被特别着意设计得同 X Render 扩展协同工作,实现了 PDF 1.4 图像模型。有趣的操作包括笔划和三次 Bézier 样条曲线,转换与合成半透明图像,反锯齿文本渲染。Cairo 的设计是可移植的,且允许可挂接的绘制后端例如图像、glitz、png、ps、PDF、svg、quartz、GDI 和 xlib。目前 Cairo 已经过大约两年的开发,在 GDK 和 Mozilla 即将到来的版本中应该能看到部署。Cairo 的主要目标是使处理屏幕上的高端 2D 图形更容易,然后轻松打印它们。可挂接后端允许应用程序使用相同的代码绘制和打印。

Cairo 后端之一,名为 glitz,基于 OpenGL 实现了 Cairo。这里有一篇上佳的论文说明了glitz 的细节。既然 Cairo 同时实现了 xlib 和 OpenGL 后端,我们可以在两者间做一直接性能比较。在已发表的基准测试中,OpenGL 的速度在所有地方都以 10 到 100 比 1 的比率击溃了 XAA。这样巨大的性能差异正是由于 glitz/OpenGL 对图形芯片上3D硬件的运用。比较 glitz 和 xlib 上的 Cairo 是一个展现3D硬件具有在 2D 屏幕上绘制之完美能力的好方法。

DRI 与 OpenGL

DRI,直接渲染机构7,实现了与 X 服务器协作的 OpenGL。DRI 有四个主要组件。首先,libGL 提供 OpenGL API,并作为在多个驱动间的切换器。其次,存在一套用于编程图形芯片的硬件相关的 DRI 库。对于DRI 驱动未能提供的 OpenGL 特性你需要一套软件后备实现。这个后备实现由 Mesa 提供。注意 Mesa 是一套完全的 OpenGL 软件实现。一块没有提供任何加速的卡仍然能够通过将每一个函数都交给 Mesa 来实现 OpenGL8。最后,就是 DRM,直接渲染管理器。DRM 驱动运行于内核,管理着硬件并提供必要的安全保护。

DRI 有意思的方面在于名字当中的 direct 代表的那部分。每个使用 DRI 的应用程序直接(directly)对视频硬件编程。这和 X 大异其趣,在那里你发送绘制命令给服务器,由服务器代表你对硬件编程。 DRM 内核驱动协调多个用户防止冲突。此模型的优点在于 OpenGL 绘制能够在无须进程切换及传输数据至主控服务器开销的情况下发生。一个缺点是图形卡必须处理大量图形上下文切换。工作站级卡一般能应对裕如,但部分消费级卡不行。Microsoft 已经撞上这个问题,并要求 DirectX 10 硬件提供高级硬件上下文切换支持。

DRM 还实现了比普通用户拥有更多能力的主控用户的概念。这些额外能力允许图形设备被初始化以及GPU 资源的消耗受到控制。当前的 X 服务器,以根权限运行着,作为 DRM 主控用户工作。实际上并无 DRM 主控用户运行在根权限下的真实要求,而且存在一个初步的补丁移除此要求。

一旦硬件缺少某种特性,Mesa 就以软件实现它。这称为软件后备。人们有时被这个绕住了。他们说他们的 OpenGL 没有被完全加速而X服务器一切正常。再想想看。两款驱动都运行在相同的硬件上。 OpenGL 未能完全加速,因为它提供了很多需要加速能力的特性,而 X 仅提供少量此类特性。如果你利用了同时存在于两款驱动 API 中的特性,他们可能都会被加速。如果没有,那就开始动手编程来修复对应的驱动。

安全性与根权限

Linux 内核包含了约 1000 万行以根权限运行的代码。X 服务器包含了 1600 万行代码,其中大多数运行在根权限下。如果搜寻安全漏洞,你认为最好下注在哪一处呢?其实并无技术理由要求 X 服务器以根权限运行。打着跨平台兼容性的旗号,当前的 X 服务器以根权限运行,以便从用户空间直接对视频硬件编程。 Linux 有个方案针对这种情况。你可以把特权代码放到设备驱动里,无须特权即可运行用户空间应用。一款一般的显示卡的特权设备驱动在 100KB 左右。那可是比 1600 万行少得多的代码需要审核。

怀旧版硬件

任何视频硬件,低档至 VGA 适配器,都可以运行 X 服务器,而且 Mesa 会非常乐意以软件实现整个 OpenGL API。问题是有多快。并没有很多编程活动投注于将一块 VGA 卡变成 ATI X850。这些旧硬件能被当前的 X 服务器很好地支持。但是新系统的设计正围绕新的硬件展开,并且它们很可能在旧硬件上表现差劲。你也许应该考虑一下升级你的视频硬件;具有适当 OpenGL 性能的全新图形卡能在 40$ 的价位买到,二手价格甚至更低。作为替代,你也可选择不要升级,继续运行那些旧的对你已经够用的软件。

内核级图形支持

当内核开始引导,你面对的就是引导控制台。在 x86 平台上,最常见的引导控制台为 VGAcon。 VGAcon 使用你图形卡上的遗留硬件 VGA 支持。既然几乎所有 x86 图形卡都支持 VGA, VGAcon 为此平台提供了一个通用控制台。在非 x86 平台上你也许无法获得 VGA 硬件支持。在这类平台上你通常加载针对特定芯片的帧缓冲驱动。内核提供为数众多的 fbdev 驱动,由此范围相当广泛的硬件都被支持了。

VGA之余孽犹存

IBM PC 的原始设计定义了少数位于固定的、预知的地址的外部设备,例如 COM1 在 0x3F8。很不幸,大多数图形卡的 VGA 支持是这些位于固定地址的遗留设备之一。只要你的系统中仅存在一块图形卡,VGA 并不成问题。插入第二块,现在你有了两片都试图独占相同总线地址的硬件。

目前的 X 服务器包含处理多块 VGA 适配卡的代码。但是这些 X 服务器代码并不会感知到这些设备上的其他用户,而是会让他们乱作一团。搞乱这些程序并不好玩,所以我们需要某种方法来协调 VGA 设备的多个用户。Linux 上最佳方案就是向内核添加一套 VGA 仲裁机制。BenH 已经动手在搞一种 OLS 上讨论过的。

另一症结在于多块显卡的初始化。显卡具有 ROM,又称 VBIOS,在引导时执行以初始化硬件。出于历史原因,很多这类初始化用到了 VGA 支持。既然我们仅能有一块遗留 VGA 设备,系统 BIOS 转移了问题,仅初始化第一块显卡。在引导期间某个较迟的点初始化第二块卡也是可能的。这是通过以 vm86 模式运行第二个 VBIOS 并同等使用单个遗留 VGA 设备来达成。为了使问题更复杂,存在两种常见 ROM 格式即 x86 代码和 Open Firmware。既然供应商对他们的 Open Firmware 型号收取高额费用,在非 x86 机器上使用 x86 视频硬件是很常见的。为了让这种做法可行,VBIOS 不得不使用 x86 仿真器来运行。BenH 也在为这个问题的一种方案工作。

Fbdev,又名帧缓冲。Linux 下,帧缓冲主要用途包括:初始化硬件,检测连接的显示设备,确定它们的有效模式,设定输出模式及配置,硬件光标,黑屏处理,色彩映射,取景和休眠/恢复。内核中存在大量帧缓冲驱动,它们实现了对这些特性程度不同的支持。请注意,尽管 fbdev 接口是基于内核的,并无障碍阻止存在实现于用户空间的辅助应用 fbdev 支持。辅助应用可用在缺少源代码的时候让 VBIOS 可用。

当你运行 VBIOS 时它建立一套非常低级的、用于控制显示的入口点。这事太细节化,我不准备解释 VGAInt10VESA 之间的所有差异。作为概括, VGA 是 IBM 创立的基本硬件寄存器标准。 Int10 专注于用软件中断的方式处理显示输出。软件中断仅工作在 x86 实模式下,且除了 GRUB 之类很少被使用。支持 Int10 功能的代码来自 VBIOS,当 ROM 运行时被安装。仅允许存在一个被安装的 Int10 驱动。VESA 取代了 Int10 模式并扩展它到保护模式。配置内核时,有三个驱动: VGA 和 VESA fbdev, fbconsole 也需要加载运行,VGAcon 则总是必要的。在非 x86 系统你通常需要 fbdev 和 fbconsole。


……

篇幅限制,更多请参考原文~


原文地址 http://mxtctp.googlepages.com/GraphicsCN.html




end