2009年5月30日星期六

Linux 图形现状

在淡出 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
版本。总的后果是一批非常参差不齐的驱动,品质从良好到完全空白。
桌面选择

其它的桌面选择, Windows 与 Mac,都拥有 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
有一个优秀的热拔插系统,图形系统真的有必要开始利用它。显示屏可以从多个来源上热拔插。有一个传统的热拔插来源;有些人将新的显示卡插入热拔插背板。然而存在其它非传统的途径来获得一次热拔插。另一位用户可能正在使用你要加到你的屏幕组的显示屏,当他注销的时候你就会获得一次热拔插。你可以将一台外部监视器连接到笔记本电脑上,从而生成一次热拔插。你可以以无线方式通过
DMX 或 Chromium 这类东西连接到显示墙。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
时它建立一套非常低级的、用于控制显示的入口点。这事太细节化,我不准备解释
VGA、 Int10 和 VESA 之间的所有差异。作为概括, VGA 是 IBM
创立的基本硬件寄存器标准。 Int10
专注于用软件中断的方式处理显示输出。软件中断仅工作在 x86 实模式下,且除了
GRUB 之类很少被使用。支持 Int10 功能的代码来自 VBIOS,当 ROM
运行时被安装。仅允许存在一个被安装的 Int10 驱动。VESA 取代了 Int10
模式并扩展它到保护模式。配置内核时,有三个驱动: VGA 和 VESA fbdev,
fbconsole 也需要加载运行,VGAcon 则总是必要的。在非 x86 系统你通常需要
fbdev 和 fbconsole。
让多用户运转

Linux
乃多用户操作系统。且它一贯如此。但是连接多个用户的唯一途径就是通过串行线和网络。如果你安装多块显示卡并在本地跑多用户会怎样?此路不通。有一堆
Linux console project 这样的补丁和针对 X
的各种黑客行为试图让它运作起来。问题在于 Linux
控制台虚拟终端系统控制着本地显示卡且只能有效地支持单个用户。注意 fbdev
被多个用户使用的时候可胜任愉快,单用户的是 VT 系统。

多个本地用户在学校、监控系统、网吧甚至家里这样的地方都有应用。由于普通 PC
仅支持单 AGP 插槽,过去对多显卡支持的需求并不紧迫。多块 PCI
显卡可以工作,但性能不彰。也有带有多个 AGP 插槽的高端机器,但并不普及。PCI
Express 改变了这种状况。通过 PCI
Express,所有插槽从机理上是等同的。唯一不同的地方就是有多少通道连接到每个插槽。硬件上的变更让构建具有多个高性能显卡的系统变得轻而易举。计划中的
PCIe 支持芯片允许最多 16 块显卡共存于单一系统中。
分裂控制台

当分析控制台系统时,你会很快注意到有两种不同类型的控制台用法。系统控制台,提供引导显示并并勇于系统错误报告、恢复和维护。以及用户控制台,用户登录并处理命令行交互或编辑的普通显示。在目前
Linux 控制台系统中,两种用法都由同一套控制台代码处理。

按照用途分离控制台代码是可能的,能够修正很多 Linux
控制台当前存在的问题。一开始,系统控制台应当完全可靠且防篡改。它不必很快。它需要尽可能以最简代码实现而且它需要在系统中断和内核
panic 时保持运作。用处包括系统恢复及单用户模式。引导时显示和 kdbg
支持也是可能的。系统控制台会提供 SAK
和安全登录屏幕。为了支持无关用户登录到显示卡的每个头,它需要无关地在每个头上实现。一种访问新系统控制台的方式是通过
SysReq,控制台将覆盖你当前的显示并使用你当前的显示模式。Novell kernel
debugger 以这种方式工作。系统控制台不支持
VT,而且不存在控制台切换。既然它清楚你的显示模式,它能够在紧急情况下抢占你的显示,比如一次致命的
kernel OOPS9。

系统控制台的设计使用 fbdev
来追踪特定的模式及扫描缓冲位于何处。为了使它尽可能地可靠任何加速支持都被移除。
Fbconsole 则使用系统 CPU 直接处理帧缓冲。控制台通过利用 fbconsole
中现有位图字体支持直接绘制到输出缓冲来显示。

用户控制台是系统控制台的对立面,它需要是高性能和用户友好的。一个用户空间实现让它易于通过为每个用户创建一个进程来处理多用户。用户空间(实现)允许全速的通过
fbdev 和 DRM 的 GPU 加速。你还能轻易访问 Xft/FreeType 获得 Unicode
支持。借助适当的设计,控制台甚至允许分配不同的用户到不同的头上。通过适当编码的热键,它能够表现得和现存
VT 一样且支持控制台切换。

既然目前的控制台是合并在一起的,当你切换 VT
时你同时遇到这两种类型。新的模型中当前 VT
切换键会把用户空间控制台提供给你。 SysReq
则激活系统控制台。连接到系统控制台上的 shell
进程能运行于高优先级,让从一个失去控制的进程手里夺得控制权更轻易。
物以群分

本地多用户支持暗示着 Linux 会为用于 UI
的外设实现控制台组的概念。控制台组是发起 login console
所须硬件的集合。一个范例组包括显示器、鼠标、键盘和音频设备。登录时, PAM
将这些设备的所有权赋予登入的用户。对此概念的有趣附加是将 USB hub
或端口作为控制台组的一部分包括进来。一旦用户登入,任何接在 USB
端口上的设备也属于他们。登出时所有这些又返回到未分派设备池中。
候补的候补10

小把戏们: directfb、 svgalib、 fresco、 Y Windows、 FBUI,诸如此类。
Linux 吸引了一票想在显示代码方面一展身手的人们。在当前的 VT
模型下,这些另类显示系统在 VT 切换时导致了很多问题。切换 VT
之后,新近激活的显示系统被允许对硬件干任何它想干的事。那包括重新初始化它,重编程它以及清除它的
VRAM。当你切换回来,原始系统被指望能从更动后的硬件状态下恢复。不仅仅是这些小把戏们才在VT
切换中造成问题。你能在控制台和 X 甚至两套桌面比如 X 和 Xegl 中切换。对具有
14 个寄存器和32KB 显存的 VGA 适配卡这可能不错。但对拥有 300
个寄存器、512MB 显存和独立 GPU 协处理器的显示卡而言它不是一个良好的模型。
合作无间

我确信对此问题的最佳方案是由内核为每种显示硬件提供单独的、广泛的设备驱动。这意味着
fbdev 和 DRM
这类冲突的驱动必须并入一套可协作的系统。它还意味着一旦基于内核的设备驱动加载,从用户空间摆弄硬件的行为就应予禁止。我怀疑如果
Linux 为不同的显卡提供广泛的标准驱动,许多创建另一版本Radeon
驱动的冲动会冷却下来。

这并不表示 fresco
这样的项目不能开发他们自己的显示硬件设备驱动。只表示你不得不卸载标准驱动,然后在运行新程序之前加载你的定制驱动。这种卸载/加载行为和内核中的其它驱动并无不同。运用热键在针对同一块硬件的两个活动的显示设备驱动之间跳转(VT
切换)将不再被支持。如果基本的驱动缺乏需要的特性,较好的方案是向标准驱动提交补丁。通过在标准驱动中实现需要的扩展,所有程序能共享它们,通过用户空间控制台系统在使用它们的应用程序间切换也会很容易。

若我们继续保持提供热键在显示驱动间跳转的 VT
设计,我认为用热键在磁盘和网络驱动间跳转也被实现才是公平的。
OpenGL|ES

Khronos Group11 是一个由超过一百家成员企业发起成立的新进标准组织。Khronos
Group 最成功的标准是 OpenGL ES。OpenGL ES
针对内存紧张系统定义了一套非常有用的 OpenGL 子集。它还定义了
EGL,一套平台无关的 OpenGL GLX/agl/wgl API 等价物。"EGL
提供机制创建可供诸如 OpenGL ES 和 OpenVG 这样的客户端 API
在其上绘制的渲染图面,为客户端 API 创建图形上下文,并同步 Client API
的绘制行为,让它和原生平台渲染 API 一般无二。这允许无缝地同时运用 OpenGL
ES 和 OpenVG 做高性能的、加速的、混合 2D 和 3D 的渲染动作12。"

EGL 假设了由操作系统的其它部分提供的窗口系统的存在性。但是 EGL
的设计是平台无关的,不象 GLX/agl/wgl,EGL API
中没有什么是局限于某个窗口系统的。所有引用到本地窗口系统的地方都由屏蔽指针来处理。

Mesa 开发者已经合计出了一些提议来扩展 EGL,以便一套窗口化系统能够实现于
EGL 之上。该扩展的核心提供了一套 API
来列举可用的屏幕,设置屏幕的模式和帧缓冲配置,摇动屏幕,以及查询属性。两个领域,硬件光标和色彩映射,仍然需要
EGL 扩展加以解决。向 EGL 添加这些扩展提供了足够的硬件控制来实现一套 Xegl
这样的服务器和窗口化系统。OpenGL 加上 EGL 和 Mesa 扩展提供一套真正可移植的
API 来访问多种形式的图形硬件,范围从当前的蜂窝电话到 Playstation 3 到 PC
到图像超级计算机13。

扩展后的 EGL API 能够很好地和 Linux
匹配。它提供了一个坚实的基础来构造窗口化系统或嵌入式应用。易于使用,这使它成为研发和体验版的有趣平台。它令你集中精力到你的新应用或窗口系统,忘记所有那些和硬件打交道的复杂性。

我相信 Khronos Group 是 X.org 和 Linux
图形社区一个重要的未加利用的机遇。大多数 Khronos
标准缺乏开源参考实现、开发系统支持以及一致性测试。Khronos Group
后台中不少在销售给予 Linux 的产品系统。如果 X.org
扩大它的宪章,它能够作为一个中立的非盈利媒介在创建开源参考实现和开发基于
Linux 和 Khronos 标准的系统方面与 Khronos Group
进行接触。这种伙伴关系允许Khronos Group 成员对 X.org 作出慈善捐赠,正如
IBM 对 Eclipse 基金会所做的那样。
完美像素

完全精确到每一个像素其实是个神话。你唯一能提高的只是逼近精确的程度。误差的来源是多方面的。你
LCD
背光的均匀度,打印机墨水的一致性,数模转换的质量,纸张的反光度,颜色匹配问题,GPU
中绘制算法的不同实现,等等。OpenGL
并不保证不同实现之间的像素级精确性。要获得像素级完美性,最接近的方法是在你的每一个输出目标上使用完全相同版本的
Mesa 软件。顺便提一句,X
服务器也不是像素精确的。我的经验法则是如果差异需要用放大镜才能找到那就足够接近了。人们在这一点上往往没搞清楚。如果你丢给
OpenGL
一张位图供显示,它会原封不动地复制那些像素到屏幕上除非你让它改变它们。像素绘制精确性的讨论主要是针对直线这类可缩放的向量。

子像素反锯齿字体(Subpixel antialiased font14)并不是问题,OpenGL
提供了多种显示子像素反锯齿字体的方案。如果你选择那么做的话,OpenGL
也能使用和当前 X
字型显示严格相同的机制。既然机制相同,字型的表现也就相同。锁定到某个特定算法也令人不快,这么做会妨碍前进。例如,这篇论文(视频)探索了一种在
GPU
上生成字体的全新方法15。这里还有另一篇让人感兴趣的论文,"使用可编程图形硬件做解析度无关的曲线渲染,Loop
和 Blinn",发表于 SIGGRAPH
2005。如果字体绘制拘泥于像素级完美精度,也许就不可能应用这些新技术。这些字型由
GPU
生成,使用了硬件内建的算法,无法被用户调整。转换轮廓字型到像素然后作为混合的图像加以渲染只是显示字型的一条途径。可编程
GPU 则提供了新的替代手段。任何眼光长远的 API 都需要把这一点考虑在内。
三代同窗

在当前的 X 服务器和许多别的窗口化系统中,窗口是用 painter's algorithm
绘制到屏幕上的剪裁多边形里。 painter's algorithm
用和真实绘画一样的方式工作 –
每一个后来的层都覆盖前一层。你先绘制背景,然后以反向 Z
序绘制每个窗口。如果不存在透明并且你清楚所有窗口的来龙去脉,你可通过剪裁长方形优化此算法(正如
X
所做的),使屏幕中的每个像素仅绘制一次。性能还可通过追踪破损来提升。仅仅破损区域的窗口需要重绘,屏幕的其余部分被剪裁多边形保护起来。更进一步的收益可由"背景保存"获得。窗口化系统意识到部分组件如弹出菜单在失效时向屏幕上重绘相同的内容。"背景保存"保存了这些弹出窗口下的屏幕并在完成后替代它。

合成机制利用了近期硬件性能增进的优势。通过合成,窗口能够离屏绘制到不可见的那部分显存上。窗口管理器随即将窗口与屏幕的可见部分合成到一起。合成仍然使用
painter's
algorithm,不过既然窗口管理器总是拥有所有窗口内容,就有可能实现透明窗口。透明通过在复制到输出缓冲区时混合窗口在屏幕上的内容与前一个窗口的内容来实现。这称作
alpha 混合(alpha
blending)。大多数现代硬件支持它。绘制闪烁也通过双缓冲得以消除。在此模型下,一切仍然是
2D 并有简单的 Z 序。

高端多纹理硬件能够防止一味使用 painter's
algorithm。每个处于屏幕上关注区域的窗口将被视为独立的纹理。你绘制多边形到屏幕上以再现窗口。对每个窗口/纹理,这些多边形在顶点上都具有适当的纹理坐标,由此纹理合并器硬件会合并所有窗口/纹理并生成期望的结果。在极端情况下,整个屏幕通过渲染单个多纹理矩形来重绘!这项技术超快,既然闪烁最小化了,你可能甚至无须双缓冲。多纹理化的完整桌面可能还在今天的硬件的能力之外,但这是一个随着每一代硬件正快速提升的领域。

Xgl 实现了合成模型。虽然并非必须,Xgl 会运用一项新的 OpenGL
特性,帧缓冲对象 (framebuffer object)。通过 OpenGL 的一项扩展,FBO
允许窗口管理器治下离屏应用程序窗口的非常有效的共享。这项扩展并不那么困难,毕竟我们已经跨进程共享了
pbuffer。对于应用程序,FBO
看起来好象普通的可绘制窗口。对于窗口管理器,窗口看起来就象纹理,可以通过多纹理这样普通的绘制命令来操纵。在这个模型下,应用程序窗口仍然是
2D,但现在编写 Luminosity 这样基于 OpenGL 地窗口管理器成为可能。基于
OpenGL 的窗口管理器能使用 Z 缓冲合并窗口,并跳出严苛的 2D Z
序限制。例如,一个窗口能够变换成波状,并反复和另一个窗口相交。

最终你能够打破应用程序窗口的 2D 限制,赋予它们厚度或别的 3D
性状。比方说,弹出窗口其实可以弹出在较高的 3D
坐标处。当你将它与光源组合使用,自然形成的下拉阴影即可取 2D
下的人工构造而代之。绘制漂亮的阴影是复杂的,然而借助 OpenGL
的能力,任务变得容易许多。Sun 的项目 Looking Glass
就是这种类型的窗口管理器。在 Looking Glass 的 demo
视频中演示了窗口厚度。Looking Glass 使用一个 rootless 的 X
服务器运行现有的 X 应用。窗口由此具有了厚度,并和 CD changer demo 中的真
3D 应用共存。

3D 桌面的概念并不那么古怪。自从 Windows 1.0
的并列窗口前进到可覆盖窗口时我们已经拥有了3D 桌面—一旦 Z
序被引入,桌面即成为一非透视的 3D 空间16。看看菜单和弹出窗口,3D
概念遍及桌面。实现合成的一个主要理由在于提供下拉阴影,很明显是 3D
空间的一个 2D 再现。甚至按钮这样的控件也通过 2D 仿真被做得象
3D。何不把它们画成 3D 的,让用户控制光源呢?窗口透明显然包含着 3D
概念。我们何不干脆承认桌面是 3D 空间并使用 3D 图形来绘制它呢?
划清界限

这个主题存在一些争论。通往基于 GPU 的桌面的开源转换 Linux
真的只有一个选择- Mesa OpenGL 实现。自然我们能够克隆
DirectX,但谁来编写全部的代码和驱动? OpenGL
是个不坏的选择。无论我们构建什么,它都是 Linux
上必不可少的一项要求。它是标准化的,由 ARB (architecture review
board,体系结构评审委员会)所掌控。它设计精良,文档齐备。它的部署和应用广泛。大学教授有关它的课程,大量关于它的书籍已经写就。很酷的应用程序和游戏在它之上运行。

应该在何种层次上划分图形设备驱动的界线?XAA 和 fbdev
在低层次上划下界线。这些 API 把自己卷入到 framebuffer、bitblit
也许还有直线绘制的众多像素中去。在这一层次上图形芯片提供的任何特性不是根本不可访问就是需要芯片特定的
API 通过转码来访问。 Xgl 实现则以相当不同的方法来划这条线。界线被划在
OpenGL API 自身这样相当高的层次。我确信 Xgl
方案是较佳的选择。为了允许硅芯片在不破坏 API
的前提下演进,你期望以位于当前实现于硅芯片中的特性集之上的方式划分界限。我不相信
Linux 会从 DirectX 那样运行一堆 API
中受益。较好的模型是从真正高的层次出发,提供参考软件实现,即
Mesa,然后用加速的硬件实现,即 DRI,分片替代 Mesa。我们也拥有多个 OpenGL
实现:Mesa、nVidia 和
ATI。使用哪一个取决于你的选择,信不信由你有些人竟喜欢专有驱动。

Xgl 被设计为一项短期过渡方案。Xgl 的模型是用一套基于 OpenGL
作为设备驱动的兼容系统透明地取代现存 X 服务器的绘制系统。Xgl 将全部现存 X
API 作为主要 API 来维护。没有任何新 X API 被引入,也没有任何被废弃。Xgl
是一套高层次的、跨平台的代码库。它是一般化的代码,需要被移植到特定的
OpenGL 环境中。一项移植, Xglx,立足于 GLX API 上。另一项移植,
Xegl,工作在跨平台的 EGL API 上。注意 EGL 是一种表现 GLX、agl 和 wgl API
的平台无关的方法。通过 Mesa 扩展 EGL
能控制低层帧缓冲。该组合提供了在裸显示硬件上实现窗口化系统(类似目前的 X
服务器)所需的一切。然而 XGL是一项短期过渡设计,通过推迟对 XGL 的需求,EXA
牌创可贴很大程度上缓解了对它的需要。

一个被反复提及的争议是,因为所有那些在这个不断发展的世界上仍在使用的老旧硬件,我们不应当使用
OpenGL。对这个问题有两个解。其一,OpenGL 是一套可伸缩的
API。借助软件后备实现它能运行在最低档的硬件上。 OpenGL ES 也提供 API
profile。 Profile 是定义良好的 OpenGL API
子集。如果有必要我们能够定义一套包含可能的最小 OpenGL API 子集的最简
profile。代码尺寸应当不成问题,一个专有的 100KB OpenGL ES
实现已经可用。另一套 OpenGL ES profile
则不要求浮点支持。没有什么能够妨碍开源的对应软件的构建,如果我们选择投入资源的话。

另一个分歧是简单地在软件被设计来使用的硬件上运行它们。没人期望一台原始的
IBM PC 运行 Windows Longhorn,但是同一台 PC 可以毫无问题地继续运行 DOS。

这里的关键之处在于 OpenGL 比 EXA 更具伸缩性。在高端 EXA
的伸缩性不堪一用,它并未包含 3D 和可编程性这样的高级 GPU 特性。透过
OpenGL,就有可能对从蜂窝电话到超级计算机的所有情况都拥有单一 API。
九层之台

你有一堆缩写需要消化。感觉一下这些库是如何协同工作的例子:

App -> gtk+ -> X -> XAA -> hw

这就是当前的 X 服务器。应用程序和 toolkit 对话,toolkit 使用 xlib API 调用
X 服务器。X 服务器利用当前的 XAA 驱动绘制到硬件上。X
和应用程序位于两个不同的进程中。

App -> gtk+ -> Cairo -> X Render -> X -> XAA/EXA -> hw

Toolkit 使用新的 Cairo 库。Cairo 的行为则取决于 X Render。如果 EXA 可用,X
Render 被加速。X 和应用程序位于两个不同的进程中。

App -> qt -> Arthur -> X Render -> X -> XAA/EXA -> hw

Arthur 是 Trolltech 的 Cairo 等价物,很大程度上两者的作用是相同的。

App -> gtk+ -> Cairo -> glitz -> GL -> hw

Toolkit 使用新的 Cairo 库。Cairo 选择 glitz 后端来获得基于 OpenGL
直接渲染。一切都是加速的,鉴于 OpenGL 是直接渲染的,绘制发生在单个进程内。

App -> gtk+ -> Cairo -> X Render -> Xgl -> EGL(standalone) -> GL -> hw

这种情况下,toolkit 为 Cairo 选择 xlib 后端,从而和邻接 X Render 的 Xegl
服务器对话。Xegl 使用 Xegl 提供渲染实现。Glitz 则直接渲染到硬件。Xegl
和应用程序位于两个不同的进程中。注意 toolkit 能够选择直接使用 glitz
并在单个进程内直接渲染。

App -> gtk+ -> Cairo -> X Render -> Xgl -> GLX(X) -> GL -> hw

再一次地,Toolkit 通过 X render 和 Xglx 服务器对话。Xglx
并非独立的服务器,它是一个嵌套服务器。Xglx
也非一个普通的嵌套服务器,它利用嵌套获得输入,但在由父服务器提供的单个
OpenGL窗口内绘制自身的整个桌面。一旦进入全屏,你不再见到父服务器。存在三个进程,应用程序、Xglx
和 X 服务器。绘制在应用程序和 Xglx 之间发生,因为 Xglx
使用直接渲染。既然第三个进程,即 X
服务器,提供窗口和输入服务,它也是重任在肩。它还是 Xglx 程序的宿主。
前路17

Linux 目前成为最迟实现充分利用 GPU 优势的桌面 GUI
的主要桌面。鉴于这个既成事实,不再有任何时间压力,也许应该考虑一项长远的方案。我们能够围绕
OpenGL 和 Cairo 设计一个新的服务器。

一般而言,整个可编程图形硬件的概念并未在 xlib 和 Cairo 这样的 API
当中触及。这是非常重要的一点。一项主要的 GPU
新特性,即可编程性,简单地无法从当前的 X API 中访问。 OpenGL 通过它的
shader 语言提供这种可编程性。

当考虑新服务器的时候,理所当然将概念设计分解为两个组件:平台相关与平台无关。设备驱动属于平台相关部分,拟议中的模型里
OpenGL 被看作设备驱动,所以会有平台相关的实现。所有同其它 Linux
子系统整合的细节问题都会隐藏在特定的驱动之后。主服务器将使用跨平台
API,诸如 sockets、OpenGL 和 EGL,来实现。一套用于热拔插设备的跨平台 API
也需要规范。此服务器无须从头设计,其实质部分能够重用来自其它项目的代码,只是要合并到新路子上来。依我之见,构建一个新服务器所需代码的百分之九十五甚至更多已经有了。

模块化是构建优秀服务器的关键之处。设计应当分解为通过标准化接口沟通的独立库。这样分解让替代某个库变得容易。你可以在不同的平台上采用不同的库实现,或者在单个平台上以不同的方式实现库。自然,跨平台代码有它的优点。Mesa
库这类材料能在所有目标系统上共享。

还记得 DirectFB 是如何使用 rootless X 的吗?新服务器将通过运行软件渲染的
rootless X 来保持与遗留系统的兼容。 DRI
的直接渲染模型是良好的设计,在未来的服务器上应予保留。将 X
转为遗留状态允许在设计新服务器时获得完全的自由。

比方说,新服务器能够设计一个全新的网络协议。最近 Linux Journal 上关于 No
Machine 和 NX 协议的文章表明 X 协议能够被压缩至 200:1
甚至更多。新协议将是基于 OpenGL
的,并被设计来防止双程延迟以及提供持久图像缓存。 Chromium
是一套有吸引力的系统,支持将 OpenGL
显示分解到通过网络连接的多个显示器上。他们的网络库处理 OpenGL
状态追踪,作为防止网络流量的一种手段。

字型缓存也应当加以分析。在目前的 X
服务器中,客户端生成字型位图,然后将它们发送到服务器,在那里它们被缓存起来。这个模型排除了早先引用的论文中讨论的利用
GPU
生成字型的方法。客户端字体是好的想法。应用程序理所当然应当负责布局。但是并无实际的要求由客户端生成字型位图。

新服务器能够解决当前在网络音频和打印方面的不足。它能够支持重连会话所需要的适当的代理行为。它也应当明确地从一开始就设计为支持多用户。

事件处理是用库构建系统的良好范例。 Linux 有 evdev、kernel hotplug、HAL 和
D-BUS。这些子系统在大多数其它平台上并不存在。因此,为 BSD
设计的输入子系统看起来会和为 Linux
设计的相当不同。将主要的子系统模块化让它们能够被定制和充分利用它们运行的平台环境。比起针对不同环境的最小公分母来设计,这是一种不同的途径。

X 为世界各地的众多情报机构使用。当前的 X
服务器被认为还没有足够安全到可用于处理敏感文档。如果主要的设计工作开始进行,它能够从根基上就特别留意安全性。适当的投入会持续以确保正确的特性被实现。

长话短说,有很多工作需要完成,最近的开发已经开始解决这些问题。第一位的是
DRM 的内存管理器和打开 DRI 驱动中
FBO(帧缓冲对象)所需要的改写。第二位的是清理现有 fbdev
驱动,使它能与已有DRM
驱动的硬件协调工作。随着奠基工作的就绪,全新服务器的设计工作就可以着手进行了。
结语

我从 Xegl
的失败获得的经验告诉我,构建一个图形子系统是一项大而复杂的工作,其规模远超过一两个人所能承担的。作为一个整体,X.org
社区仅仅具有足够的资源创建单个服务器。将这些资源分配到不同的方向上只会导致一堆半途而废的项目。我理解开发者比较愿意为那些引起他们兴趣的东西工作,但是鉴于
X.org
拥有的资源,这种做法不会在近期孕育出新的服务器甚或基于旧服务器然而富有竞争力的桌面。也许
X.org 是时候释出一份路线图供所有人追随了18。

Jon Smirl

于 2005 年 8 月 30 日

授权可自由地翻译和再发布19。

0 以下的注解都是译者另加,主要目的是提供一点背景和 Linux
图形方面的进展供读者参考。首份译文完成于 2006 年 7 月 7 日,是 gogoliu
发起的《Modern X Tech. 中文翻译计划 》项目的一部分,这是 2006 年 8 月 4
日修正版,都是极细微的修正,读过的可略过。另外我花了点时间看了下 html 和
xhtml,现在的 html 和 xhtml 格式都是我手工编写的了,效果应该比
OpenOffice.org 2 生成的为佳,尺寸也小些。对译文的指教,可联络 mopz0506
[AT] gmail [DOT] com,标题请务必包含"The State of Linux Graphics"
字样。永远怀念在八年抗日战争中牺牲的国共两党将士们。

1 原文(http://jonsmirl.googlepages.com/graphics.html)发布于 2005 年 8 月
30 日,所以基本上是一年前的现状。

2 但是随着 Internet 的增大,对人们获取知识和真相的恐惧也增大了。

3 和 Jon Smirl 不同,其实 K.P. 作为 XFree86 的叛逆者,对一切 3D
化的倾向,反应并不是很积极的。 K.P. 说过,95% 的时间都是在跑
2D。译者就无所谓了,反正 95% 的时间都在跑控制台和 ncursor :)

4 X11R7.0 已于 2005 年 12 月 21 日由 X.Org 正式发布。 X11R7.1 已于 2006 年
5 月 22 日由 X.Org 正式发布。这是第一个享受模块化带来的益处的 roll-up
发布。

5 Porter-Duff 操作是 1 组 12 项用于描述数字图像合成的基本手法,包括
Clear、Source Only、Destination Only、Source Over、Source In、Source
Out、Source Atop、Destination Over、Destination In、Destination
Out、Destination Atop、XOR。通过组合使用 Porter-Duff 操作,可完成任意 2D
图像的合成。这里有 Thomas Porter 和 Tom Duff 发表于 1984
年原始论文的扫描版本 http://keithp.com/~keithp/porterduff/p253-porter.pdf

6 Cairo 1.2 已于 2006 年 7 月 1 日正式发布。另外,最近 Cairo 项目在 google
上搜索 Cairo 关键词时的排名已超过埃及城市 Cairo,稳居第一。

7
机构这个词很少在计算机方面的文章中出现。其实机构是一个很有内涵的词,也是机械方面的一种专门学问。我不喜欢架构这个词,因为架字让我感到隐含有草率的意味。我更喜欢体系结构这个说法。其实国内大概最早关于
architecture 的一本书(98年?99年?),《Software Architecture: Perspectives
on an Emerging Discipline》
影印版,印象中书名就是译成《软件体系结构》的。可惜不小心遗失了。

8 Mesa 就是作者忘了说的那个"再次"。

9 kernel OOPS 中的 OOPS 并不是某个缩写,来自英语中常说的
Oops,相当于汉语中哎呀呀,坏乐这类意思,随着时间逐步演进为特定场景下的专有名词。内核源代码的
Documents 目录下有一篇 oops-tracking.txt 文档。《Linux Kernel
Development》第18章 Debugging 有一节专门介绍 oops 的,可参考。

10 这让我回想起很久以前读过的一本描述 DEC 公司一群年轻工程师设计 PDP
小型机的故事的书,当中有个非常好的比喻,说某个改进方案是瘤子上又长瘤子。书名大概是《The
soul of a new machine》。

11 根据 opengl.org 在 The OpenGL Pipeline Newsletter
第一期(估计也是最后一期)中的官方说法,OpenGL ARB 将并入 Khronos
组织,OpenGL 也将随之和 OpenGL ES
成为同门,甚至再次融合也不是没有可能的。让我们期待此举为沉寂已久的 OpenGL
带来更多活力。

12 这段引文是来自 http://www.khronos.org/ 描述 EGL 的一段话。

13 graphics supercomputers 一般指比较强的可视化工作站,SGI 那种类型的。

14 LCD 上 RGB
三色其实是靠得很近的三个点,所谓子像素反锯齿字体就是利用这个特性增强 LCD
显示效果的一种手段。

15 论文中述及的方法已经在XGL中实现了。

16 这是说,此3D空间的对象并不具备透视关系,比如距离近点看起来大点什么的。

17 在那崎岖崎岖里看阳光......

18 很想译为:噫!树一帜而天下影从,此其时也!

19
译完了,似乎懂了一些,其实没有懂。一篇文章想要译得神完气足,实在需要不菲的心力。以我的理解,作者对
Linux
图形的现状显然是失望的,我无法译出这种味道来。感到非常对不起作者,可是没办法。

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

没有评论: