Modern X Tech. Chinese Translation Project
[[the_state_of_linux_graphics]]
Last edit on Jul 8, 2006 8:05 AM by Anonymous

此页面已经完成了它的历史使命,那就是不断提醒我,你还有件工作没完成呢 :)

最终版本请看

html 版本 http://mxtctp.googlepages.com/GraphicsCN.html
PDF 版本 http://mxtctp.googlepages.com/GraphicsCN.pdf




另,原文现在已经移到 http://jonsmirl.googlepages.com/graphics.html 了。


原文链接 http://www.freedesktop.org/~jonsmirl/graphics.html

Linux 图形现状(注1)

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

俱往矣

今年是 X server 的二十一岁生日。脱胎于 1984 年的 Athena 项目,过去的那些年中,它很好地满足了 Unix 社团的需要。X 已经被广泛应用,推动着今天的大多数 Linux 桌面。这篇 Wikipedia 文章(http://en.wikipedia.org/wiki/X_Window_System (注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 并不只是为了制造更华丽的视觉效果。有大量利用 3D 能力生成的效果只是虚饰,但仍有些真正的理由运用 3D。简单来说 3D 快过 2D,没有人动手使他们的 2D 功能更快,所有的硅工程师都转向了 3D 。你能够完成快速、任意的图像处理,例如色彩空间转换,拉伸/卷曲,等等。我曾见过某些花费主 CPU 几秒钟才完成一帧的超级复杂的过滤操作在 shader 硬件上以实时达成。支持任意色彩映射的不同的 Windows 色深(同时支持 8、16、24 位窗口)。为项目管理者提供极快的屏幕翻转/旋转,为视力不良者提供全屏缩放,等等。分辨率无关性允许对象以任意分辨率/尺寸渲染,当显示到屏幕上的时候再降低/提高取样精度。更多有意思的应用在后面讨论 Windowing (泛指,难译啊,就这么放着吧。反正就是那个意思)的小节里阐述。

当前的 X.org 服务器

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

X,作为操作系统

X 究竟是一个应用程序还是一个操作系统?在这里( http://h30097.www3.hp.com/docs/dev_doc/DOCUMENTATION/HTML/AR5NHATE/TOC.HTM )有一份优秀的参考文献帮助我们理解一个 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操作(注4)。这些操作允许图面以不同的方式合并。它们与OpenGL纹理和纹理操作的概念非常相似,但是仅仅是相似而不是完全一致。

XAA
XAA,即X加速架构,其于Xfree86 4.0 版本中导入。为了达到跨平台的可移植性,XAA没有使用内核设备驱动而在用户空间实现了2D显示驱动。用户空间驱动虽然可以正常实现,但是由于不是基于内核驱动的,因此Linux内核无法追踪X是如何在硬件上运行。而且X是直到你的系统启动后才开始运行。你一定是希望在启动过程当X启动出错时有一个显示画面,是不是?所以在系统启动过程中,又用一个文本(控制台)模式的驱动来实现画面显示。一般文本模式显示驱动常常用的是VGAcon。所以在Linux上,就有了两种显示设备驱动,即X和console。它们都试图控制相同的设备。XAA、console以及基于Linux内核的虚拟终端,这三者的结合导致了很多矛盾和冲突,而且以后只能会更多。

EXA
EXA取代了现有的2D的XAA设备驱动,以便延长当前的服务模式的使用寿命。它提供越来越多的高级驱动和内存管理API以加速X渲染扩展。一开始,EXA作为全部硬件的解决方案而出现,其中包括一些陈旧的硬件。但实际上并不是这样。如果硬件的缺少渲染所要求的alpha渲染硬件支持,这时虽然EXA仍然可以通过更好的内存管理来增加这些芯片的性能表现,但是其它的你就什么都做不了了。所以最后结果是EXA表现比较好的的硬件几乎也都是具有OpenGL驱动的硬件,除了像nv和i128这样具有3D性能,但却没有OpenGL驱动的硬件外。EXA将会不断的扩展来体现芯片的3D性能,如我们所希望的。简陋的像茅屋似的EXA会继续服务一段时间,但不会长久。关键的一点是要记住,EXA/render仍然是庞大的OpenGL的一个微小的子集。伴随着时间我们会想得到越来越多的特性的。

Cairo(注5)

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 and OpenGL

DRI,即直接着色基础架构,其与X协作实现OpenGL。DRI有四个主要的组成部分:首先是libGL,它提供OpenGL API,在各种驱动中作为一个转换器。下一个是与硬件细节相关的DRI库,它处理具体显卡芯片。你也需要对于DRI驱动无法提供的OpenGL特性的实现。这个实现有Mesa提供。注意,Mesa是一个完全的OpenGL的软件实现。这样,即使不提供硬件加速,显卡也能依靠Meta实现OpenGL的每一个功能。最后,有一个DRM,即直接着色管理器。DRM在内核内部运行,管理硬件并提供相关安全保护。
DRI的一个有意思的地方是名字中的"direct"。每一个使用DRI的用户程序直接对显卡编程。这与X不同,当你向X提出绘图请求时,X代替你控制硬件。DRM核心驱动程序来协调不同用户以避免产生冲突。这种模式的优点是直接进程OpenGL绘制,而不用进行高层进程交换和向控制系统传输数据。这样做的一个缺点是显卡不得不处理大量的图形上下文交换。这对于一个专业图形卡可能是一个正常的功能,但对于一些业余显卡却无法做到。微软已经遇到了这个问题,已经要求符合DirectX 10显卡具有高级硬件上下文切换支持功能。
DRM也实现了主用户的概念。主用户可以比一般用户具有根多的权力。这些附加的权力允许显卡进行初始化和对GPU资源的使用进行控制。当前的X是作为root运行的,作用相当于DRM管理者。实际上,没有要求DRM管理者作为root运行。已经有了一个初级的补丁来去掉这种要求。
当硬件没有实现一个特性时,Mesa使用软件实现这个特性。这称为软件模拟。人们对此很困惑,他们说他们的OpenGL不是完全的硬件加速而他们的X却是。想一想,这两种驱动都是运行与相同的硬件至上。OpenGL不是完全加速是因为它提供很多可加速的特性。而X只提供很少。如果选一个同时在两个驱动中的API,它们都会被加速。如果没有的话,那么应该开始编写和安装相关的驱动。

DRI与OpenGL

DRI,直接渲染机构(注8),实现了与X服务器协作的OpenGL。DRI有四个主要组件。首先,libGL提供OpenGL API,并作为在多个驱动间的切换器。其次,存在一套用于编程图形芯片的硬件相关的DRI库。对于DRI驱动未能提供的OpenGL特性你需要一套软件后备实现。这个后备实现由Mesa提供。注意Mesa是一套完全的OpenGL软件实现。一块没有提供任何加速的卡仍然能够通过将每一个函数都交给Mesa来实现OpenGL(注9)。最后,有一个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 之余孽犹存

最初的IBMPC设计对于外围设备使用固定的地址查找定位,如众所周知,COM1的地址为0x3F8。这就对硬件一定的限制。不幸的是,大部分显卡支持的VGA规范就是这些遗留的具有固定地址的设备类型之一。当你的系统中只有一块显卡的时候,VGA不会有什么问题。但是一旦插入第二块显卡,这时你就会有两块显卡想要控制相同的总线地址了。

当前的X系统中具有控制多显卡的代码。但是X的代码无法应用于多用户。它会把他们混为一团。在Linux上最好的解决办法是想内核中加入一个VGA仲裁机制。BenH已经在做这方面的工作。在OLS上有相关的讨论。

另一个是多显卡的初始化问题。显卡具有ROM,其中存储内容被称为VBIOS。它在启动时初始化硬件。遗留的问题是显卡的初始化要利用VGA支持,但却只能有一个VGA设备。系统BIOS无法解决这个问题而只能初始化第一个显卡。当然,也可以在启动过程的后期初始化第二块显卡。这可以通过在虚拟86下运行第二块显卡的VBIOS,然后协调使用VGA设备来解决这些问题。让事情变得更复杂的是有两种通用的ROM格式:x86编码和Open Firmware(开放引导固件)[这句翻译有些问题]。因为厂商对它们的Open Firmware模式的使用收取高昂的费用,所以在一台非X86机器上使用X86显卡是很普遍的。这就需要使用X86模拟器来运行VBIOS。BenH也做了这方面的工作。

Fbdev,也被称为帧缓存。在Linux中,由于帧缓存的存在,我们需要初始化硬件,检测联接的显示器,确定它们的可用的使用模式,设置扫描输出模式和配置、硬件指针、图像消隐,颜色映射、面板和挂起/恢复。在内核中有很多的帧缓冲驱动。它们实现对这些特性的各种不同程度的支持。注意到没有,fbdey的接口是基于内核的。这并没有阻碍在用户空间助手程序的实现。助手程序一般用于在程序不可用的场合调用VBIOS。

当运行VBIOS时,它建立一组用来控制显示的底层交互接口。现在这些概念已经变得很清楚了!我不会解释VGA、Int10和VESA之间所有的差异。概括来讲,VGA是由IBM制订的基础硬件寄存器标准。Int10通过使用软中断来实现显示输出。软中断只能在x86实模式下使用,除了GRUB等软件,Int10已经不再被使用了。支持Int10的代码存在于VBIOS。当启动时,代码从ROM中被载入。但只能安装一个Int10功能的驱动。VESA实现了Int10模式,并将其扩展到保护模式下。这样当配置内核时,就有三个驱动:VGA、VESA fbdev(由fbconsole来装载运行)和VGAcon(包含所有内容)。在非x86系统上,你通常需要的是fbdex和fbconsole。


VGA 孑遗

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

Making multiuser work
Linux从一开始就是一个多用户操作系统。但这只是在本地单一顺序模式或网络模式的基础上实现的。如果安装多个显卡并且实现本地多用户,那会发生什么?它将无法运行!现在已经有补丁来试图在X上实现这一目标,如Linux console project and various hacks。但是问题是Linux控制台虚拟终端系统控制本地显卡,它只能有效地支持单用户。注意,fbdey能被多个用户同时正常的使用。它处于单用户的虚拟终端系统。[这句有问题,是吧?]

本地多用户系统能应用于像学校、监控系统、咖啡馆,甚至在家中这样的地方。过去对要求提供多显卡的支持的呼声不高,这主要是主流的PC只有一个AGP插槽。多个PCI接口的显卡能够工作,但性能并不高。而高端的计算机有多AGP插槽,他们却不是主流。现在PCI express总线改变了这一切。有了PCI express,所有的插槽的功能都是一样的,唯一点不同就是插槽具有的通道数量。硬件的改变使得配置一台具有多个高性能的显卡的计算机石很容易的一件事。正在开发中的PCIe芯片最多能在单一的系统中支持十六块显卡!

分离控制台(注)

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

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

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

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

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

Grouping Hardware
本地多用户支持意味着Linux将会实现"以用户界面为导向的控制台组"这一理念。控制台组是一个可登陆的控制台的硬件组成的集合。这样一个的例子将包括一个显示器、一个鼠标、一个键盘和音频设备。在用户登陆时,PAM(Pluggable Authentication Module可插入认证模块)把这些设备的使用权分配给登入用户。一个有趣的扩展是在控制台组中加入一个USB hub或端口。这样在用户登入系统后,任何插入USB端口中的设备也属于该控制台组。当用户登出时,所有的的设备都被释放到未分配设备池中。

候补的候补(注20)

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


协作无间
我相信这个问题最好的解决办法是内核为每个图形设备提供单一的全面的设备驱动。这意味着相互矛盾的驱动如fbedy和DRM必须合并成一个互相协作的系统;它也意味着当装载内核设备驱动时应阻止对硬件的访问。我觉得如果Linux能为各种显卡提供标准驱动的话,那些想为显卡编写不同版本驱动的想法就变得毫无必要而消失了。
这当然并不是意味着像frsco这样的项目不能为显示硬件开发它们自己的设备驱动。而是意味着在运行这种新程序(指的是需要特殊的设备驱动的程序)之前,你将不得不卸载Linux中的标准的驱动,然后装载自定义的驱动。这种显卡驱动的卸载以及装载与系统中的其它设备的驱动没什么不同。不应再支持使用热键在两个同时活跃的控制同一块硬件的驱动之间切换。如果一个驱动缺少某种需要的特性,最好的处理方法是向标准的驱动中加入补丁。通过在标准程序中实现需要的扩展,所有的程序都可以共享使用它们。这样也很容易让用户空间的控制台系统在使用这些驱动的程序之间切换。
如果我们继续目前使用热键在驱动程序之间切换的这种VT设计,我想为了公平,我们也应该实现使用热建在磁盘和网络等设备的不同驱动之间切换。

OpenGL|ES

Khronos Group是一个由超过一百家成员企业发起成立的新进标准组织。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到图像超级计算机(注14)。

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

三代同窗

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

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

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

Xgl实现了合成模型。虽然并非必须,Xgl会运用一项新的OpenGL特性,framebuffer objects(帧缓冲对象)。通过OpenGL的一项扩展,FBO允许窗口管理器治下离屏应用程序窗口的非常有效的共享(注20)。这项扩展并不那么困难,我们已经跨进程共享了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空间(注)。看看菜单和弹出窗口,3D概念遍及桌面。实现合成的一个主要理由在于提供下拉阴影,很明显是3D空间的一个2D再现。甚至按钮这样的控件也通过2D仿真被做得象3D。何不把它们画成3D的,让用户控制光源呢?窗口透明显然包含着3D概念。我们何不干脆承认桌面是3D空间并使用3D图形来绘制它呢?


划分界限

在这个问题上有一些争论。Linux真的只有使用Mesa实现的OpenGL图形库标标准来实现向以GPU为基础的桌面转变吗?我们当然也可以实现DirectX的克隆,但是谁来编写这些代码及相应的驱动呢?OpenGL是一个不错的选择。我们有必要在Linux上使用它,无论我们做什么。它被ARB(OpenGL架构评审委员会)制定和标准化;它被良好的定义和设计,有相应的标准文档;它被广泛传播和使用;教授们在大学课堂上讲授以其为内容的课程;有许多关于它的书;在它之上有很多非常酷的游戏和程序。

应该在什么级别来划分图形设备驱动与用户程序的界限呢?XAA和fbdev把分界线划分在级别很低的位置。它们把它们的API与帧缓存中的像素操作、位块传输(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。没有添加新的API,也没有削减任何的API。Xgl是以高层的、跨平台的代码实现。它是通用的代码,需要运行于特定OpenGL环境。一种环境是Xglx,其提供GLX API。另一个是Xegl,致力于提供跨平台的EGL API。注意EGL是GLX、agl和wgl API集的平台独立的实现。有了Mesa扩展,EGL就能处理底层的framebuffer。这种结合提供了在裸机上实现一个窗口系统(类似当前的X系统)需要的任何东西。但是,Xgl只是一个短期的转换方案,其只是用来降低对EXA的依赖[这句翻译有点问题]

似可译为:然而XGL是一项短期过渡设计,通过推迟对XGL的需求,EXA牌创可贴很大程度上缓解了对它的需要。

一个争论不休的话题是,因为有许多的老硬件,所以我们不应该使用OpenGL。对于这个问题有两种解决办法。首先,OpenGL是可升级和扩展的API。它可以通过软件模拟的方式运行在低级的硬件上。其次,OpenGL ES也提供OpenGL API的一个很小的实现。它是经过良好设计的OpenGL API的一个子集。如果需要,我们可以设计一个最小的模型来实现最小的OpenGL API。代码大小不是问题。包含所有的100KB的OpenGL ES是可行的。而且,OpenGL ES不需要浮点运算支持。只要我们愿意花费一些气力,没有什么事可以阻止开源的发展。

另一个争论是只应该使用为正在使用的而不是新硬件编写的软件。没有人会期望一台原始的只能运行DOS 的IBM PC能没有任何问题的运行Windows Longhorn。

关键一点是相对于EXA来说OpenGL是可以不断升级扩展的。EXA却是无法向更高的层次发展。它没有包括高级的GPU特性,如3D和可编程性。有了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程序的宿主。



前路(注9)

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

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

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

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

还记得DriectFB是如何使用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是时候释出一份路线图供所有人追随了(注21)。

Jon Smirl

于 2005年8月30日

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

(0)译者注:由于本文还未定稿(也许永远不会定稿?),下面注解可能不是按顺序的。
(1)译者注:原文发布于 2005 年 8 月 30 日。
(2)译者注:但是随着 Internet 的增大,对人们获取知识和真相的恐惧也增大了。
(3)译者注:X11R7.0 已于 2005年12月21日由 X.Org正式发布。
(4)译者注: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
(5)译者注:终于译到有意思的地方了啊,Cairo + giltz 双剑合璧,非同小可啊。
(6)译者注:LCD上RGB三色其实是靠得很近的三个点,所谓子像素反锯齿字体就是利用这个特性增强 LCD 显示效果的一种手段。
(7)注:这是我翻译的内容,仅供参考。译者可以决定其取舍。- - - 译者曰:不错,欢迎 :) 我也把我的贴出来供大家斟酌。只是 DRI and OpenGLSecurity and root 其实我已经译出,正在润色之中,还没有帖上来。以后我注有(待补)的就是这种情况,(空缺)就是还没有动手的,请大家留意不要冲突。如果有人认领哪一小段的,也请注明。谢谢。
(8)译者注:机构这个词很少在计算机方面的文章中出现。其实机构是一个很有内涵的词,也是机械方面的一种专门学问。我不喜欢架构这个词,因为架字让我感到隐含有草率的意味。我更喜欢体系结构这个说法。其实国内大概最早关于 architecture 的一本书(98年?99年?),《Software Architecture: Perspectives on an Emerging Discipline》影印版,印象中书名就是译成《软件体系结构》的。可惜不小心遗失了。
(9)译者注:Mesa 就是作者忘了说的那个"再次"。
(10)译者注:在那崎岖崎岖里看阳光......
(11)注:不好意思噢!呵呵,希望没有打乱你的工作。这篇文章在这个项目前,我就开始翻译的。只不过英文too bad!没办法申请这个项目。这是其中我认为比较满意的。所以才贴出来,只是想给mopz0506兄做一个参考。mopz0506兄可以对其修改,也可以删掉。我只是添加内容。毕竟你的英文比我好多了。至于添加我的名字就不想了,很高兴能为中国的开源做一些事情。 - - - 收到,尊重你的意思。其实我也差不多,本来只想匿名的,都是被 gogoliu 拉进来的 :) - - - mopz0506翻译水平高,你不留名,我都不好意思在我的拙(译)作留名了。 ;) 前面那位朋友若是有意可以认领另外的文档,随时欢迎。 - - gogoliu 呵呵,水平不行啊!我对图形编程是一窍不通,有些术语都是边译边查。我觉得我们虽然不是专业人士,但对质量的要求还是应该高一些。起码要做到意思正确。我做不到这一点。不过正在学习中...不论是英文,还是专业知识。希望有一天能真正翻译出自己喜欢的东西。呵呵!
(12)译者注:这段引文是来自http://www.khronos.org/ 描述EGL 的一段话。另,Khronos 的简体中文版译文非常非常的烂。
(13)译者注:这让我想起一本描述DEC公司一群年轻工程师设计PDP小型机的故事的书,当中有个非常好的比喻,说某个改进方案是瘤子上又长瘤子 :)
(14)译者注:graphics supercomputers一般指比较强的可视化工作站,SGI那种类型的。
(15)译者注:这一段我自己也不甚满意。先 post 出来,以后慢慢修正吧。
(16)译者注:VT 是 virtual terminal,虚拟终端的缩写。
(17)译者注:论文中述及的方法已经在XGL中实现了。
(18)译者注:思之再三,还是觉得很难译得让没有背景知识的同志看懂。
(19)译者注:kernel OOPS中的OOPS并不是某个缩写,来自英语中常说的Oops,相当于汉语中哎呀呀,坏乐这类意思,随着时间逐步演进为特定场景下的专有名词。内核源代码的 Documents目录下有一篇oops-tracking.txt文档。《Linux Kernel Development》第18章Debugging有一节专门介绍 oops 的,可参考。
(20)译者注:如果一次没读明白,可多读几次 :)
(21)译者注:很想译成 "噫!树一帜而天下影从,此其时也!"