原文地址:https://keithp.com/~keithp/talks/usenix2001/xrender/,本文仅做翻译。

X Rendering Extension(或者说render,XRender)是X11核心协议的扩展,用于在X Server中实现图像合成。

在2000年的Usenix技术大会,介绍了X渲染环境以及将X呈现出来所需的能力。 在过去的一年中,新的扩展,作为标准XFree86发行版的一部分,已经被设计和实现。
X渲染扩展解决了核心X渲染架构中的许多问题,并且没有显著地增加协议解释或是增加服务器负担。通过借用Plan 9窗口系统的基本图像合成概念并提供复杂和可扩展的字体渲染,XFree86可以更好地支持现有应用程序,同时鼓励用户界面的新发展。在精确的多边形光栅化和图像变换领域仍然有很多工作有待我们去完成。

在2000年的Usenix会议上,学者提交了一篇论文,讨论了核心X渲染架构中存在的问题以及可能的解决方案。根本问题是:渲染系统的编码实践,事后很快就会被废弃。急于发布原始的X11标准,没有时间留给技术问题的解决。最重要的问题是那个时代的硬件不能支持复杂的交互式窗口系统。

去年的一些论文 - alpha合成,抗锯齿,亚像素定位和梯形 - 都包含在这个新的扩展中。扩展的其他部分,如客户端字体管理是在扩展设计期间开发的。

扩展版本的开发以开放的方式进行,并且从窗口系统社区的各处获得输入。参与XFree86,KDE,Qt,Gdk,Gnome和OpenGL的人都为最终架构的形成作出了贡献。

但是规范的某些方面仍然不够完善。工具包和应用程序开发从XRender中收益,因此它已经成为XFree86发行版的重要部分。它还传达出了一个强烈的信号:XFree86已准备就绪并能够将X Window系统的开发推向未来。

三、渲染模型

XRender 与核心X 渲染系统不同, 用RGB模型替换基于像素值的模型 。虽然客户端仍然可以看到像素值,但每个像素值(即使存储在像素图中的像素值)都有一个与之关联的颜色值。这样就可以提供基于颜色的自然成像,同时仍允许应用程序在必要时查看像素值。

这种改变带来的一个问题是伪彩色视觉效果。最好的方法是动态分配颜色以最接近地匹配显示的颜色。但是,伪彩色桌面的数量正在减少,取代它的是静态颜色模型。这样可以大幅减少执行时的负担,同时仍然允许应用程序在伪彩色硬件上运行。 (事实上​​,目前的XFree86实现甚至没有这种简化的支持,但迄今为止还没有提交错误报告。)

除了将图像数据呈现为颜色值之外,Render还使用由Porter和Duff两人在1984年正式提出的 图像合成操作取代核心协议中的光栅化操作 。这些操作指令通过引入透明度和允许当图像一层一层的叠加时颜色数据混合的方式来获得颜色数据。

Porter-Duff混合模型统一了半透明的概念:像素完全被非不透明值(non-opaque value)覆盖,具有局部覆盖的概念,其中一部分像素被覆盖而剩余部分未被覆盖。渲染使用部分覆盖来近似抗锯齿;沿着几何对象边缘的部分覆盖的像素被渲染为好像它们是半透明的。

Render中的所有操作都是根据原始运算操作合成的,产生一致的模型同时支持最简单的实现。渲染模型的设计宗旨是:通过尽可能简单的方式提供必要的服务操作,使其与现代工具包和应用程序配合良好。

3.1 图像合成

从物理学上来说,半透明物体会吸收一些照射在它身上的光但不是全部。物体的颜色会影响哪些波长吸收最多。在视觉上,半透明物体似乎会影响其他物体的颜色和亮度。

部分遮挡视野的和半透明物体的效果是相似的;在足够精细的分辨率下,在对象边缘附近的点处采样的颜色将显示为上层和下层颜色的混合。Porter和Duff使用此属性将部分覆盖转换为半透明。

光对半透明对象的影响可以通过将半透明对象的颜色与旁边对象的颜色混合来模拟。 当处理计算机图像时,半透明度可以描述为对图像集合颜色数据的数学运算。Porter和Duff利用颜色数据和称为“alpha”的每像素不透明度值组成的公式建立模型。利用这些公式,可以执行许多直观的图像处理。

3.1.1 图像合成运算

由Porter和Duff定义的运算独立地在每个像素的每个颜色通道上操作。为了显示每个像素点的每个通道上的操作方程式被缩写。

常见的合成操作是 将一个图像放在另一个图像上 。上层图像的透明区域中可以显示底层图像,不透明区域隐藏底层图像,而半透明区域将两个图像混合在一起。 将像素的“alpha”定义为0到1之间的数来衡量不透明度 ,那么可以用一个简单的等式将两个像素颜色组合在一起:

Porter和Duff称之为“ over ”运算。

另一个常见的操作是 用另一个图像掩盖本图像 ;透明区域从图像中移除,而不透明区域使得图像可见。

这是“ in ”运算。 他们提出了完整的合成代数和其他操作,但是此扩展中只需要这两个。

这个模型的一个重要方面是它创建了一个新的图像描述——为每个像素附加了一个值“alpha ”。该值测量像素的“不透明度”,并且可以通过渲染函数和颜色分量进行操作。

3.1.2 目标 Alpha

有时,创建本身半透明的合成图像很有用,换句话说,包含alpha值。这种效果可以通过增加操作来实现,该操作可以产生复合α值和颜色值。 对于“over”运算操作,复合alpha值定义为:

“in”运算符复合alpha值是:

生成的图像现在可用于其他渲染操作。

3.1.3 预乘 Alpha

上面用于计算“over”运算的等式中,可以看到alpha和颜色分量的计算方式存在不对称性:

将图像数据重新指定为“由alpha预乘”。 图像中的每个颜色分量由该分量乘以相应的alpha值代替 。Blinn 指出:预乘图像在运行长序列操作时可以轻易获得正确的结果,而非预乘图像则涉及笨拙的计算。因此所有四个元素在一个方程式中表示为:

3.2 渲染合成基础

由Russ Cox和Rob Pike设计的Plan 9 Window系统提供了基于Porter-Duff合成的统一渲染操作:

所有像素操作都是通过此操作完成的,该操作在整个渲染系统中提供了一个简单且一致的模型。渲染采用此操作但稍做扩展。Plan 9仅提供OVER运算,Render允许使用Porter和Duff定义的所有运算符和专为从OpenGL中来的抗锯齿图形的绘制而设计的特殊运算。渲染操作如图1所示。

使用此基本渲染操作,扩展通过指定隐式掩码的构造来定义几何操作,然后在一般操作中使用该隐式掩码。通过沿边缘生成具有部分不透明度的隐式掩码来 模拟消除锯齿图形

四、基本渲染对象

与大多数X扩展一样,Render添加了许多X服务器端数据类型来封装上面表达的概念:

4.1PictFormat

PictFormats保存将像素值转换为红色、绿色、蓝色和Alpha通道所需的信息。服务器具有与屏幕上的各种视觉效果对应的图片格式列表,表示pixmaps存储的各种格式的数据的附加格式。有两种格式: 索引和直接 。索引的PictFormats包含像素值和RGBA值的列表,而直接PictFormats为R,G,B和A中的每一个保持位掩码。

直接PictFormats可能包含所有R,G,B和A,或者它们可能只包含R,G和B或仅包含A。后两者为单独的alpha掩码和没有目标alpha通道的服务器视觉效果提供必要的格式。

每个索引PictFormat都有一个关联的色彩映射表,从中可以分配相关的颜色值。这允许多个不同的索引格式共存,允许应用程序选择最佳匹配格式,并为以该格式呈现的窗口选择关联的色彩映射。

4.2Picture

Picture将X Drawable(窗口或Pixmap)与合适的PictFormat连接起来。它们还可以作为放置与图片相关的渲染状态的便利位置。当PictFormat不提供Alpha通道时,Picture可能会引用外部Alpha通道,该通道表示为另一个Picture,其中仅使用alpha通道。如果没有此外部Alpha通道,则每个像素的图片隐含alpha值为1。

Picture是Render中的通用像素数据表示。没有为任何操作提供明确的像素值。纯色或重复图案时,图片具有“重复”属性,设置后,通过沿两个轴将图片内容平铺展开,图片将被视为无限数据源。

这允许纯色填充,平铺和点画是对象到对象数据复制的特殊情况。

一个附加属性允许在具有已知子像素几何形状的显示器上优化图像显示。在这样的环境中,应用程序需要控制每个颜色组件的合成。通常合成运算操作使用相同的alpha值混合所有四个组件。当合成源码中的mask图片操作数设置为“ComponentAlpha”属性时,R,G,B和A值被解释为孤立地在每个通道上操作的alpha值。

4.3 复合请求

Render扩展的核心是单个请求: 所有其他渲染都是通过基本复合渲染操作的Composite定义的 。 此运算符在Render规范中定义如下:

此请求通过使用op合成运算将特定的src矩形和dst矩形的掩码结合。坐标是相对于它们各自的绘图原点的。渲染被剪裁为dst drawable的几何体,然后剪切到dst剪辑列表,src剪辑列表和掩码剪辑列表。

如果指定的矩形超出src,那么如果src设置了repeat属性,则src图片将被平铺以填充指定的矩形。否则渲染会剪切到src几何体。

如果指定的矩形超出了掩码,那么如果掩码设置了重复属性,则将平铺掩码图片以填充指定的矩形,否则渲染将剪切到掩码指定的几何体。

如果src,mask和dst的格式不同,并且其中一种格式可以保持全部而不会丢失精度,则它们将转换为该格式。或者,服务器将每个操作数转换为保留格式。

如果mask为None,则将alpha设置为常量值1。

当dst具有剪辑通知集合时,如果渲染操作未被src或掩码剪切,则发送NoExpose事件,否则发送一系列 GraphicsExpose事件,覆盖dst中由src或mask剪切渲染的区域。

关于这个定义的一些重要说明:

  • 操作数格式不需要匹配;渲染会自动将转换为最精确的格式或内部保留格式,以防所提供的格式无法在不丢失的情况下保存数据。
  • 通过设置源图片的“重复”属性可以控制实心填充、图案和图像复制。
  • 通过使用适当的图像填充“mask”来绘制几何对象,然后可以使用这些对象来模板化任何图案。
  • 4.4 客户提供的即时数据

    由于Pictures是Render中像素数据的唯一表示,因此应用程序生成的图像必须使用现有内核中的X PutImage请求来将该信息传输到服务器。未来的扩展可以提供新的图像传输功能:消除中间缓冲和提供标准图像压缩算法,以减少网络环境中的大量图像数据所消耗的带宽。

    五、文本渲染

    字体管理和文本渲染一直是让架构设计者和应用程序开发人员感到头疼的部分。 X试图将字体抽象为简单的位图图像和描述为简单字符串或整数值的相关数据。图像的光栅化留给了X服务器,应用程序无法通过标准的X接口访问高级字体信息,例如字距调整表和连字。

    许多应用程序在面对X文本模型时,放弃并完全在应用程序中实现所有文本显示——将生成的显示图像直接发送到X服务器。 X文本渲染代码被降级为按钮和对话框消息的绘图标签。这样不能有效地利用图形系统的巨大加速潜能。

    在为Render扩展构建类似系统的过程中,有几个因素共同将开发导向一个全新的方向。 第一个是认识到应用程序需要直接访问完整的字体信息,最好是原始字体文件本身 。只有通过这种直接访问才能确保应用程序能够获得有关字体的所有信息。

    最初的渲染协议通过扩展现有的X字体服务协议来提供此访问。应用程序和X服务器通过X字体服务器和应用程序请求高级字体属性。通过现有的字体文件格式或者使用某个格式,来显示所有的信息,这是一项艰巨的任务,因此在开发扩展图像的组成部分时推迟了这项任务。

    改变文本系统方向的第二个因素是:关于PDF文件和嵌入字体数据的讨论 。与其他应用程序一样,PDF文件要求显示仅应用程序可用的字体。在现有字体框架中使用应用程序提供的字体的唯一可移植机制是:让应用程序通过在应用程序中创建自定义字体服务器来使用X字体服务协议。这为所有X应用程序增加了另一个可能的故障点,因为现在无论何时访问字体都会依赖于此字体服务器;在操作字体名称时,添加大量此类应用程序将显着降低应用程序的性能。

    Render的一个目标是以更直接的方式解决这个问题。让应用程序根据它提供的数据构建字体是一个显然的解决方法,通过X协议流发送字形图像,而不是通过X字体服务协议的后门。

    最后一个因素是关于Unicode编码字体的 。在绘制单个字形之前,X客户端接收字体中每个字形的几何信息,以及整个字体的最小值和最大值。使用轮廓字体时,获取此信息的唯一方法是必须首先光栅化每个字形。对于具有256个字形的字体,这不是一个巨大的负担。但是汉字形编码可能包含数千个字形,从而引起一些性能问题。Unicode字体可能包含数百万个字形。此时,光栅化所有字形并将所有这些信息传递给应用程序变得不切实际,特别是当只有一小部分字体可能被显示时。

    因此需要设计一个新的允许字形的增量光栅化的文本系统。在X服务器中增量光栅化字形的问题就是在于应用程序需要增量的请求有关字形的信息,这将需要在协议层增加数据往返传输过程。往返是网络环境中的一个严重的性能问题,并且在应用程序启动时会感受性能损失(这已经是某些X应用程序的痛处了)。

    综上所述——提供复杂的字体信息,客户端生成字体,在不增加往返次数的情况下增量的光栅化字体——引导出一个非常简单的解决方案。 X渲染扩展没有字体支持。相反,它为应用程序提供了一种机制,用于缓存服务器中的字形图像并光栅化它们的序列。应用程序负责定位字体,光栅化字形并生成几何信息。

    这种方法解决了所有三个问题,同时降低了扩展的复杂性。应用程序可以直接访问字体文件,从而可以访问其中包含的所有信息。由于所有字体都是由客户端提供的,因此PDF文档中的嵌入字体与任何其他字体一样能得到有效地处理。最后,没有字体处理的往返,这可以减少应用程序启动时间。它还减少了网络流量,因为只有应用程序实际使用的字形才会在网络上传输。由于缺少从未在屏幕上绘制的字形的信息,因此字形图像消耗的额外流量大于补偿。

    在网络流量分析一节中将会显示,在应用程序启动时间和网络利用率方面均有显着下降,即使对字形中的每个像素使用8位也是如此。

    5.1 字形管理

    在Render中消除服务器端字体带来了一些新的挑战。应用程序仍然需要一种简洁有效的方法来沿固定基线渲染一系列字形。Render提供了多个字形的存储,称为“GlyphSets”。 每个字形本质上都是一个带有附加几何信息的图片,用于描述相对于基线绘制字形的位置以及下一个字形的偏移量

    通过任意32位数字在GlyphSets中命名字形:没有假定的编码。这些名称以8,16或32位编码传输:没有提供可变长度编码。

    在当前的XFree86实现架构中,相同的字形共享相同的存储。这适用于GlyphSet,以及来自一个或多个客户端的多个GlyphSet。客户端提供字形的消除了服务器端存储开销。

    通过使多个应用程序在特定字体的字形光栅化过程中协作,可以改善字形的重复渲染和传输。作者设想了一种协作的共享内存机制: 其中同一地址空间中的应用程序可以一起工作构建所需的字形 。因为用于引用X服务器内的GlyphSets名称的生命周期不大于创建名称的X连接,所以Render协议允许每个客户端为每个GlyphSet都有自己的名称。只要还有名称存在,GlyphSet就会存在。

    需要为这种共享设计重要的基础架构。由于这些更改不会影响Render协议本身,因此可以在需要时进行此设计。

    5.2 字形绘制

    一旦将所需的字形传递给X服务器,客户端就会使用CompositeGlyphs请求之一显示其序列(有三个,对应于三个字形的名称编码)。这些请求显示了许多字形列表,每个字形列表都沿着两个轴的位置增量的从前一个字节偏移。对所选字形集的更改可以写入字形列表中。这非常类似于核心X文本显示请求附件垂直位置调整。位置调整也从8位扩展到16位。简单文本显示的一个例子如图2所示。字形位置沿着基线用插入符号标记,每个字形图像的范围用虚线框标出。 每个字形包含从字形图像的左上角到渲染原点的距离、字形图像的尺寸以及从渲染原点到下一个要绘制字形位置的距离

    当近似抗锯齿时,多个操作覆盖相同区域时,使用OVER运算一系列单独操作会生成不准确的值,而alpha值既不透明也不非透明。问题是两个目标的子像素几何在转换为覆盖值时会丢失。

    OVER运算通过假定每个目标覆盖所有像素中的相同比例,来获得两个目标子像素覆盖的最优近似。在绘制文本时,更好的近似是假设字形实际上不重叠;此时,像素的整个覆盖区域是每个像素覆盖的区域的总和。

    发出字形绘制请求时可以创建中间Picture对象;请求中的所有字形都使用ADD运算符呈现给此中间图片。然后,使用请求中指定的运算将生成的图像渲染到目标。当渲染结果不受其使用影响时,服务器可以自由地消除中间Picture对象,例如当每个像素仅用一个位表示字形或者没有任何字形重叠时。

    5.3 网络流量分析

    字形在客户端内光栅化并传输到X服务器,显然我们会担心这些字形给网络带来额外负担。虽然字形图像确实会增加从客户端发送到服务器的流量,但是从服务器到客户端字形的流量将被消除。

    事实证明,对于典型的应用程序执行场景来说,消除的从服务器发送到客户端的字形矩阵和字体名称的流量,远远高于由字形图像产生的额外流量。表1显示了使用少于256个字形的拉丁字体的两个常见应用程序的网络利用率。

    有趣的是,仅仅选择适当的字体就需要大量的字节;通过ListFonts请求和回复表示。由于核心X架构仅提供基于字符串的字体匹配,因此必须在客户端内实现更复杂的方案,从而需要从服务器传输有关可用字体的信息。

    从小型Latin-1编码字体到较大的汉字或Unicode字体,会显着增加传输矩阵的数据量,但是不会显著增加字形数据量:汉字或Unicode字符集中的大部分不会被用到。

    值得注意的是,核心X架构需要往返列表或打开字体。由于应用程序通常在启动时打开许多字体,因此这些额外的往返可以大大增加初始化应用程序所需的时间。

    六、 Xft

    消除X服务器内的字体处理会将字体文件管理的负担转移到客户端。在不同客户端之间进行字体管理的不同机制导致需要标准字体文件访问库。 Xft库的设计基FreeType库,提供常见的字体命名,字体文件管理和字体自定义 。Xft不是Render扩展的一部分,但它是提供应用程序字体访问的整体架构的重要组成部分。

    Xft还通过提供统一的API来允许与旧X服务器的某种程度的兼容性。应用程序可以检测何时发生这种情况以便进行补偿。幸运的是,随着XFree86变得越来越普遍,传统X服务器的数量应该继续减少,这使得这种兼容性在很大程度上是不必要的。

    设计Xft的一个重要前提是:库不应该向应用程序隐藏底层光栅化引擎和字体文件。任何想抽象化此类访问的尝试,都只会阻止应用程序充分利用字体文件和光栅化引擎中的功能。

    这里存在明显的冲突——一方面,Xft提供了足够的抽象功能来掩盖核心X字体和基于渲染的字形之间的差异,另一方面,它提供了对基础字体文件(如果存在)的完全访问。应用程序需要为任何可能性和行为一致性做好准备。Xft由工具包库使用。

    6.1 字体名称

    选择字体的过程可以分为两个阶段:首先定位适当的面,然后根据额外的应用属性修改面以创建正确的字形图像。完成此操作后,有关字体的属性将传递回应用程序。

    Xft将这些步骤统一到一个机制中。 XftFontName是一个类型化的属性列表;每个元素都有一个名称和一个值。每个可用的面由XftFontName表示,该XftFontName包含由底层字体机制提供的面部属性。

    应用程序构造XftFontNames并将它们呈现给API。库将此名称与可用面匹配以选择最佳面,然后用其他额外的属性设置情况来调整最终字形显示的光栅化。生成的字体匹配一个名称,其中包含有关字体的其他信息,例如加载面的源文件。

    虽然名称的内部表示是属性列表,但现有应用程序可以方便地将字符串表示转化为内部表示。 Xft字体名字的一般格式是:

    典型的规范可能是“times-12”,它指定了来自时间族的12点字体。使用加粗和斜体的默认值会产生中等加粗的罗马变体。Family和size域是可选的;Xft将根据剩余的属性选择合适的famliy和默认大小。在最小的情况下,字体名称将始终匹配。

    七、渲染仍在完善中

    上面描述的这些Render部分不是很有争议;他们已经在实践应用中表现出很好的工作性能,也已经使用了一段时间,为它们存在的价值提供了一定程度的保证。扩展的另外两个组件,目前尚未在XFree86中实现。接下来将讨论这些组件, 多边形渲染和图像变换,以及当前思路中的已解决和未解决的问题

    八、多边形渲染

    从OpenGL中获取提示,Render将服务器渲染的几何对象减少到最小集合。复杂对象在客户端内进行细分,并作为一组基本对象发送到服务器。这最大限度地减少了服务器内的实现工作量以及测试实现的一致性所需的工作量,同时不会给应用程序带来太多麻烦。

    Render提供两个独立的原始对象:三角形和梯形。两者都是根据32位定点数定义的,它使用24位作为值的整数部分,8位作为小数部分。允许更精确地定位多边形的顶点,并消除当对象被捕捉到整数网格时引起的视觉噪声。

    通过使用坐标定位三个顶点来指定三角形。梯形更复杂,因为它们设计的目的是准确地表示细分。梯形由两条划分梯形顶部和底部的水平线和两条由任意点指定的附加线表示,如图3所示。四条线之间的任何区域都是梯形(或者,在简并的情况下,是一个三角形)。允许梯形顶部或底部的点不重合,使得多个梯形的边缘精确对齐;不管这些物体的水平范围如何,相同的线都可以用于所有梯形。

    多边形的光栅化似乎是一个没有争议的问题,用线条连接一系列顶点并填充覆盖区域。但确实会出现一个问题:适当的渲染精度如何定义。

    8.1 精确与不精确

    首要问题是:是否应该为多边形的精确像素化制定标准。为了简化执行的情况的验证,核心X协议要求所有对象必须精确像素化,但这样也基本上消除了对象的效用。最初的核心X协议很难进行有效的软件实现,只有最近的一些硬件,可以在灵活的硬件中实现协议中的大部分。应用很少使用超过零宽度线的X几何对象。

    对于不精确的光栅化,像素化的不确定性使得源码很难使用;应用程序必须接受显示出来的图像可能存在很大差异。现在的问题是如何限制像素化的过程。OpenGL具有相对较弱的不变性需求,因为其追求软件和硬件实现高性能混合。现有的应用程序对像素化的一致性有很高的需求,那么这就需要制定额外的约束了。

    精确的像素化需要规范:指定的像素化必须合理地执行。一个不好的规范会使得每次执行都是无用的。应用程序也需要精确的规范来需要混合服务器端和客户端渲染,同时规范必须是直接执行的。

    渲染同时提供上述两种模式。不精确的方式用来映射到现有的GL-优化的硬件,精确的方式提供给应用程序实现对屏幕上显示出的渲染效果的严格控制。

    8.2 不精确多边形

    不精确的多边形必须满足以下要求:

  • 邻接边缘的精确匹配。当指定沿公共边缘邻接的两个多边形时,如果每个多边型的边缘由相同的坐标表示,那么两个多边形的并集内的所有像素值的和必须是1。
  • 平移不变性。在多边形或者绘制目标沿着任何方向上的任何整数像素平移以后,多边形的像素化结果必须仍然相同。
  • 锋利的边缘。当使用锋利的(非锯齿)边缘对多边形进行光栅化时,每个像素的alpha掩码将仅包含1或0。
  • 顺序独立性。使用不同的顶点顺序定义的两个相同的多边形必须生成相同的结果。
  • 这些约束旨在通过多边形细分和平移,最小化视觉假象。现有的硬件可以满足这些要求。

    8.3 精确多边形

    精确多边形是一项巨大的挑战。对于尖锐的多边形,规范很简单:绘制中心点落在多边形内的像素,而外部的像素则不绘制。根据X模型的要求,如果多边形内部偏右,中心恰好位于边缘的像素点会被绘制,如果多边形内部偏下,落在垂直边缘的中心点会被绘制。

    给定32位坐标空间,当表示仅用于剪切的不大于64位的值时可以精确的使用。

    对于平滑(抗锯齿)多边形,解决方案还不太确定。如果要计算每个像素被多边形覆盖的比例,这个计算成本是非常高的;需要至少192b来精确计算梯形两侧相交的像素所覆盖的区域。

    虽然这可能会比遵照核心协议渲染一个宽椭圆时的计算量小一些,但是没有证据表明实现这个特定的规范会比计算量小一些的规范更好。像素覆盖的区域仅是将多边形形状过滤为像素集合需要的正确值的粗略近似,只要它提供相同的值,简单的规范也是“正确”的。

    一种思路是将相关像素分成三种:完全被多边形覆盖、完全没有被覆盖以及部分覆盖。覆盖和未覆盖情况下的像素结果是显而易见的。

    对于被梯形部分覆盖的像素,通过将梯形剪切到像素边界来计算覆盖率。在梯形边缘与像素的边界相交的情况下,沿像素边缘的坐标表示为16位小数值。在此精度下,当仅要求32位的算数计算时会产生小于分之一的像素覆盖误差。

    另一个建议是从扩展中删除多边形,只留下不精确的多边形。关于需要在现有列表中添加什么不变量,是否影响不精确多边形情况下的硬件加速,这些问题仍然存在。

    哪个选择最有意义取决于是否能设计实现如上定义的精确多边形或者其他精度规范。由于缺乏有效的实现,应用程序倾向于使用不精确多边形,而精确多边形给X服务器带来了承重的负担。

    8.4 多边形请求

    假设有一个渲染一系列梯形的请求和三个渲染三角形的请求。一个梯形由左、右、上、下四条边界线确定。从图3中可以看出,在梯形中指定左右边缘的坐标并不需要与水平对齐。

    对三角形的请求仅在三角形顶点的编码方面存在不同,请求格式取自OpenGL API。第一种形式提供一个简单的三角形列表,每个三角形中每个顶点有一个点。另一种形式的顶点列表是:将三角形的最后两个顶点与下一个顶点结合形成另一个三角形。在列表资源用尽之前优先使用后者。最终的三角形的表示将一个三角形的第一个、第三个顶点与下一个顶点组合在一起,形成后续的三角形。

    这些请求均作为基本复合运算中的隐式掩码元素运行。源图片提供RGBA元素。如果有为每个顶点提供RGBA值的附加请求,那么源图像会被替换为通过在多边形中插入指定的RGBA顶点颜色而生成的新图像。这样只需要几个请求就可以实现各种颜色效果。

    九、图像变换

    添加到Render中的最终操作涉及在X服务器中进行图像数据变换。任意仿射变换提供了大量可行的操作,可以通过用于3D纹理映射的硬件进行加速。

    变换请求从源图像中获取一个四边形区域并将其映射到目标范围内的四边形区域中。顶点被顺序映射,这允许从源到目的图像数据的任意仿射变换。

    目标四边形形成一个隐式的alpha掩码,其可用于平滑变换过来的图像的边缘。通过在转换期间过滤source Picture来创建源图像。暂时还不需要提供过滤精度设置情况;通用硬件滤波器和一些使用数字信号处理技术的高质量滤波器都是必要的。

    我们的最终目的是在实现架构中可以根据需求提供额外的滤波器,并在协议内创建一种机制来传递他们的一些特征。

    关于过滤器执行中的边缘效应还有其他问题;可能需要额外的滤波器参数来生成超出源图像边界的像素值。

    还有一项建议是将目标限制为梯形而不是一般的四边形。这样可以简化基本实现,同时不会过度限制未来的优化。

    十、历史和现状

    自从X服务器从单色变为彩色,对Render扩展的需求一直存在。原始渲染架构不适合处理颜色数据。然而,最近基于X的应用程序开发的兴起和随之而来的X技术的重振,为研发注入了活力。

    历史上,太过于关注与现有X应用程序和X服务器的兼容性。现有的X渲染系统限制了新的开源用户界面环境Gnome和KDE。KDE接受了环境的限制并充分利用了它们。Gnome用客户端的渲染取代了服务器端的渲染,将X协议转变为简单的图像传输系统。缺乏硬件加速和远程应用程序性能的下降表明,研究应该转向考虑提供一些服务器端的支持。

    截至Usenix 2000,尚未制定所有扩展的正式协议,但此问题引起了广泛的关注,一系列构想被提出。其中一位与会者Rob Pike描述了他和Russ Cox为Plan 9窗口系统开发的渲染系统的架构。该环境中的简单统一架构只需要稍微扩展一下即可实现。

    Render扩展协议在XFree86社区中讨论了几个月。一旦它稳定下来,就开始实施,目标是在2000年8月之前制作一个可行的抗锯齿文本演示。

    此时,该实现仅提供对基本合成原语以及文本原语的支持。上面讨论的与抗锯齿多边形光栅化有关的问题,排除了多边形或图像变换操作的实现。一旦该问题得到解决,就可以完成实施。

    从去年10月开始,XFree86服务端中正在开发一种加速Render扩展架构。由于协议的设计目的是在现代硬件上进行实现,因此原语本身的实现相对简单。正如所料,硬件加速提供了巨大的性能优势。本人和Mark Vojkovich对简单图像合成的初步度量表明,硬件的运行速度比合理优化的C代码快40倍。

    2000年末,对Xft的支持已集成到了Qt工具包中,该工具包构成了K桌面环境的基础。该工具包为所有渲染操作提供了完整的抽象,因此修改工具包即可在所有KDE应用程序中提供抗锯齿文本。在Qt 3.0中,还提供了一个新的渲染功能,允许应用程序在屏幕上合成图像。

    还有一些尝试在Gnome社区中使用Render。但是,在从Gtk + 1.2过渡到Gtk + 2.0之前,为实现完全转化需要将太多的底层X字体模型传递给应用程序。 Gtk + 2.0应该在明年准备就绪,为社区提供另一个完全独立的X字体工具包。

    十一、结论

    X渲染扩展提供了一个可在X窗口系统中使用的全新渲染模型。它的小尺寸和低级原语允许在提供完整功能的同时以合适的大小实现。这些原语旨在紧密匹配应用程序要求和硬件功能。

    X桌面已经开始转型,在几个工具包和应用程序套件中引入了抗锯齿文本。工具包曾经努力想要提供现代用户界面技术,Render介入并允许应用程序使用自己的语言。新的应用程序已经将X转变为简单的图像传输协议;事实证明,核心渲染系统在现代世界中基本上是行不通的。渲染将绘图带回服务器,充分利用硬件的功能,同时允许应用程序再次在网络上高效运行。Render允许X窗口系统再次支持高级开源桌面环境。