作者:魏永明
MiniGUI 1.1.0 版本引入的新 GDI 功能和函数
本文向读者展现了 MiniGUI 的最新开发成果,即在 MiniGUI 1.1.0Pre4 版本中引入的新的 GAL 和新的 GDI 功能和接口。这些接口最终会出现在 MiniGUI 1.1.0 正式版本中。本文主要内容包括 GAL 和 GDI 的关系,新 GAL 引擎的接口特点,新 GDI 的功能增强以及接口应用范例等等。
1 引言
在本系列开发指南(四)中,我们具体讲解了 MiniGUI 的 GDI 函数及其使用。我们也曾提到,MiniGUI 现有的 GDI 函数和功能,尚不能对机顶盒、瘦客户机等高端嵌入式系统提供良好支持。因此,我们在 MiniGUI 1.1.0 版本的开发中,重点对 GAL 和 GDI 进行了大规模的改良,几乎重新编写了所有代码。这些新的接口和功能,首先出现在最近发布的 MiniGUI 1.1.0Pre4 版本中,为了帮助开发人员正确理解和使用这些功能,特撰文说明新 GAL 和新 GDI 的接口和功能。
2 新 GAL 和新 GDI 接口的设计目标
首先,MiniGUI 旧的 GDI 接口非常简单,其功能主要集中在位图和块操作上,例如 FillBox 函数、FillBoxWithBitmap 等等,而缺少对其他高级图形操作的支持,比如椭圆、圆弧、样条曲线等等。其次,旧的 GDI 接口还缺少基本的光栅操作功能。这里的光栅操作,指欲设定象素如何与屏幕上已有的象素进行运算。最基本的光栅操作功能是二进制的位操作,包括与、或、异或以及直接设置等等;高级的光栅操作包括透明处理和 Alpha 混和。这些 GDI 功能的缺乏,使得 MiniGUI 在机顶盒、瘦客户等系统中应用时,显得"力不从心"。再次,旧的 GDI 接口基本上没有考虑到任何硬件加速功能。我们大家都知道,显示卡自身提供的硬件加速功能,能够大大提高图形程序的运行速度,使得画面流畅而自然,假如 GUI 系统不能充分利用这些硬件特性的话,则图形处理能力将大打折扣。最后,旧的 GAL 设计存在抽象层次太高的问题,导致了 GAL 引擎臃肿,且重复代码很多,也不便于进行代码上的优化。
综上所述,我们参照闻名的跨平台游戏和多媒体函数库 SDL(Simple DirectMedia Layer)对 GAL 引擎结构进行了重新设计,并且重新实现了所有的 GDI 函数,使得新的 GDI 接口具备如下特性:
能够充分利用硬件特性,包括显示内存和硬件加速能力。
支持高级图形操作,包括基本光栅操作、透明处理和 Alpha 混和。
增强了剪切区域处理能力,有助于优化图形输出函数。
增强了原有的 BITMAP 接口,使之支持透明和 Alpha 通道。
充分利用嵌入式汇编代码进行代码优化。
下面将重点讲述新的 GAL 功能和新的 GDI 接口。
3 新 GAL 功能特性
新的 GAL 结构来自闻名的跨平台游戏和多媒体库 SDL(Simple DirectMedia Layer)。目前提供了对 Linux FrameBuffer 的支持,计划在将来提供对 X、SVGALib 和 VGL(FreeBSD)等等图形库的支持。
3.1 GAL 和 GDI 的关系
大家都知道,MiniGUI 的 GAL 是一个图形抽象层,提供给上层 GDI 函数一些基础的功能和设施。在先前的设计中,GAL 可以看成是 GDI 图形驱动程序,许多图形操作函数,比如点、线、矩形填充、位图操作等等,均通过 GAL 的相应函数完成。这种设计的最大问题是无法对 GDI 进行扩展。比如要增加椭圆绘制函数,就需要在每个引擎当中实现椭圆的绘制函数。并且 GDI 治理的是剪切域,而 GAL 引擎却基于剪切矩形进行操作。这种方法也导致了 GDI 函数无法进行绘制优化。因此,在新的 GAL 和 GDI 接口设计中,我们将 GAL 的接口进行了限制,而将原有许多由 GAL 引擎完成的图形输出函数,提高到上层 GDI 函数中完成。GAL 和 GDI 的新的功能划分如下:
GAL 负责对显示设备进行初始化,并治理显示内存的使用;
GAL 负责为上层 GDI 提供映射到进程地址空间的线性显示内存,以及诸如调色板等其他相关信息;
GAL 负责实现快速的位块操作,包括矩形填充和 Blitting 操作等,并且在可能的情况下,充分利用硬件加速功能;
GDI 函数实现高级图形功能,包括点、线、圆、椭圆、圆弧、样条曲线,以及更加高级的逻辑画笔和逻辑画刷,必要时调用 GAL 接口完成加速功能;
尽管某些显示卡也提供有对上述高级绘图功能的硬件支持,但考虑到其他因素,这些硬件加速功能不由 GAL 接口提供;而统统通过软件实现。
这样,GAL 主要实现的绘图功能限制在位块操作上,比如矩形填充和 Blitting 操作;而其他的高级图形功能,则全部由 GDI 函数实现。
3.2 显示内存的有效利用
新的 GAL 接口能够有效利用显示卡上的显示内存,并充分利用硬件加速功能。我们知道,现在显示卡一般具有 4M 以上的显示内存,而一般的显示模式下,不会占用所有的显示内存。比如在显示模式为 1204x768x32bpp 时,一屏象素所占用的内存为 3M,还有 1M 的内存可供给用程序使用。
因此,新的 GAL 引擎能够治理这部分未被使用的显示内存,并分配给应用程序使用。这样,一方面可以节省系统内存的使用,另一方面,可以充分利用显示卡提供的加速功能,在显示内存的两个不同内存区域之间进行快速的位块操作,也就是常说的 Blitting。
3.3 Blitting 操作
在上层 GDI 接口在建立内存 DC 设备时,将首先在显示内存上分配内存,假如失败,才会考虑使用系统内存。这样,假如 GAL 引擎提供了硬件加速功能,两个不同 DC 设备之间的 Blitting 操作(即 GDI 函数 BitBlt),将以最快的速度运行。更进一步,假如硬件支持透明或 Alpha 混和功能,则透明的或者 Alpha 混和的 Blitting 操作也将以最快的速度运行。新的 GAL 接口能够根据底层引擎的加速能力自动利用这些硬件加速功能。目前支持的硬件加速能力主要有:矩形填充,普通的 Blitting 操作,透明、Alpha 混和的 Blitting 操作等。当然,假如硬件不支持这些加速功能,新的 GAL 接口也能够通过软件实现这些功能。目前通过 GAL 的 FrameBuffer 引擎提供上述硬件加速功能的显卡有:Matrox、3dfx 等。
在通过软件实现透明或混和的 DC 间 Blitting 操作时,新的 GAL 接口利用了两种有效的优化措施:
在 i386 平台上,充分利用嵌入式汇编代码进行优化处理;比如在处理 32 位色模式下的普通 Blitting 操作时,在利用普通的 C 库函数,即 memcpy 进行位块复制时,由于 memcpy 函数是以字节为单位进行复制的,从而无法利用 32 位 CPU 对 32 位字的处理能力,为此,可以使用嵌入式汇编,并以 32 位字为单位进行复制,这将大大提高 Bliting 操作的处理速度。
对源 DC 进行 RLE(Run Length Encoding)编码,从而对象素的处理数量最小化。RLE 可以看成是一种图象压缩算法,Windows BMP 文件就利用了这种算法。RLE 是按水平扫描线进行压缩编码处理的。在一条扫描线上,假如有大量相同的象素,则不会保存这些象素点,而是首先保存具有相同象素点的数目,然后保存这些象素点的值。这样,在进行透明或者混和的 Blitting 操作时,可以大大降低逐点运算带来的速度损失。但是,假如在最坏的情况下,比如所有水平扫描线上的象素点都具有和相邻点不同的象素值,则 RLE 编码反而会增加象素的存储空间(最坏的情况是原有空间的两倍),同时也会降低 Blitting 操作的速度。因此是否使用 RLE 编码,要根据情况而定。新的 GDI 接口在指定源 DC 的透明和 Alpha 通道值时,可以指定是否使用 RLE 编码。
3.4 有效分辨率
新的 GAL 引擎可以设定一个不同于实际显示分辨率的有效分辨率。比如实际的显示分辨率是 1024x768,则可以在 /etc/MiniGUI.cfg 文件中指定比实际分辨率低的有效分辨率。这种特性有利于在 PC 上调试需要运行在较小分辨率系统上的应用程序。比如:
[system]
gal_engine=native
ial_engine=native
[native]
defaultmode=320x240x16
其中在 defaultmode 当中指定了有效分辨率为 320x240,16 则表示颜色深度,即 16 位色,或者称为每象素的二进制位数。需要注重的是,对 VESA FramBuffer 设备,必须指定和当前颜色深度一致的颜色深度值。对其他的 FrameBuffer 设备,假如能够支持多种显示模式,则会根据 defaultmode 指定的模式设置当前分辨率。
3.5 新 GAL 的限制
需要注重的是,新的 GAL 结构只打算支持线性显示内存,并且只支持 8 位色以上的显示模式。假如要支持低于 8 位色的显示模式,则可以选择使用老的 GAL 和 GDI 接口。在配置 MiniGUI 的时候,你可以指定是否使用老的 GAL 和 GDI 接口。默认情况下的配置是使用新的 GAL 和 GDI 接口,需要使用老的 GAL 和 GDI 接口时,应进行如下的配置:
./configure --disable-newgal
另外,新的 GAL 接口支持 Gamma 校正和 YUV Overlay,但目前尚未在 GDI 接口中体现这些功能。在新的版本中,会逐步添加相应的 GDI 接口。
4 新的 GDI 接口
4.1 新的区域算法
新的 GDI 采用了新的区域算法,即在 X Window 和其他 GUI 系统当中广泛使用的区域算法。这种区域称作"x-y-banned"区域,并且具有如下特点:
区域由互不相交的非空矩形组成;
区域又可以划分为若干互不相交的水平条带,每个水平条带中的矩形是等高,而且是上对齐的;或者说,这些矩形具有相同的高度,而且所有矩形的左上角 y 坐标相等。
区域中矩形的排列,首先是在 x 方向(在一个条带中)从左到右排列,然后按照 y 坐标从上到下排列。
在 GDI 函数进行绘图输出时,可以利用 x-y-banned 区域的非凡性质进行绘图的优化。在将来版本中添加的绘图函数,将充分利用这一特性进行绘图输出上的优化。
新