分类:
2006-06-13 16:48:50
基于 Linux 和 MiniGUI 的嵌入式系统软件开发指南(五)
MiniGUI 1.1.0 版本引入的新 GDI 功能和函数
()
自由撰稿人
2001 年 10 月
在本系列开发指南(四)中,我们详细讲解了 MiniGUI 的 GDI 函数及其使用。我们也曾提到,MiniGUI 现有的 GDI
函数和功能,尚不能对机顶盒、瘦客户机等高端嵌入式系统提供良好支持。因此,我们在 MiniGUI 1.1.0 版本的开发中,重点对 GAL 和
GDI 进行了大规模的改良,几乎重新编写了所有代码。这些新的接口和功能,首先出现在最近发布的 MiniGUI 1.1.0Pre4
版本中,为了帮助开发人员正确理解和使用这些功能,特撰文说明新 GAL 和新 GDI 的接口和功能。
首先,MiniGUI 旧的 GDI 接口非常简单,其功能主要集中在位图和块操作上,例如 FillBox
函数、FillBoxWithBitmap 等等,而缺少对其他高级图形操作的支持,比如椭圆、圆弧、样条曲线等等。其次,旧的 GDI
接口还缺少基本的光栅操作功能。这里的光栅操作,指欲设定象素如何与屏幕上已有的象素进行运算。最基本的光栅操作功能是二进制的位操作,包括与、或、异或
以及直接设置等等;高级的光栅操作包括透明处理和 Alpha 混和。这些 GDI 功能的缺乏,使得 MiniGUI
在机顶盒、瘦客户等系统中应用时,显得"力不从心"。再次,旧的 GDI
接口基本上没有考虑到任何硬件加速功能。我们大家都知道,显示卡自身提供的硬件加速功能,能够大大提高图形程序的运行速度,使得画面流畅而自然,如果
GUI 系统不能充分利用这些硬件特性的话,则图形处理能力将大打折扣。最后,旧的 GAL 设计存在抽象层次太高的问题,导致了 GAL
引擎臃肿,且重复代码很多,也不便于进行代码上的优化。
综上所述,我们参照著名的跨平台游戏和多媒体函数库 SDL(Simple DirectMedia Layer)对 GAL 引擎结构进行了重新设计,并且重新实现了所有的 GDI 函数,使得新的 GDI 接口具备如下特性:
下面将重点讲述新的 GAL 功能和新的 GDI 接口。
新的 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 主要实现的绘图功能限制在位块操作上,比如矩形填充和 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 接口利用了两种有效的优化措施:
3.4 有效分辨率
新的 GAL 引擎可以设定一个不同于实际显示分辨率的有效分辨率。比如实际的显示分辨率是 1024x768,则可以在
/etc/MiniGUI.cfg 文件中指定比实际分辨率低的有效分辨率。这种特性有利于在 PC
上调试需要运行在较小分辨率系统上的应用程序。比如:
|
其中在 defaultmode 当中指定了有效分辨率为 320x240,16 则表示颜色深度,即 16 位色,或者称为每象素的二进制位数。需要注意的是,对 VESA FramBuffer 设备,必须指定和当前颜色深度一致的颜色深度值。对其他的 FrameBuffer 设备,如果能够支持多种显示模式,则会根据 defaultmode 指定的模式设置当前分辨率。
3.5 新 GAL 的限制
需要注意的是,新的 GAL 结构只打算支持线性显示内存,并且只支持 8 位色以上的显示模式。如果要支持低于 8
位色的显示模式,则可以选择使用老的 GAL 和 GDI 接口。在配置 MiniGUI 的时候,你可以指定是否使用老的 GAL 和 GDI
接口。默认情况下的配置是使用新的 GAL 和 GDI 接口,需要使用老的 GAL 和 GDI 接口时,应进行如下的配置:
|
另外,新的 GAL 接口支持 Gamma 校正和 YUV Overlay,但目前尚未在 GDI 接口中体现这些功能。在新的版本中,会逐步添加相应的 GDI 接口。
4.1 新的区域算法
新的 GDI 采用了新的区域算法,即在 X Window 和其他 GUI 系统当中广泛使用的区域算法。这种区域称作"x-y-banned"区域,并且具有如下特点:
在 GDI 函数进行绘图输出时,可以利用 x-y-banned 区域的特殊性质进行绘图的优化。在将来版本中添加的绘图函数,将充分利用这一特性进行绘图输出上的优化。
新的 GDI 增加了如下接口,可用于剪切区域的运算(include/gdi.h):
|
在 MiniGUI 1.1.0 版本正式发布时,我们将添加从多边形、椭圆或圆弧等封闭曲线中生成剪切域的 GDI 函数。这样,就可以实现将 GDI 输出限制在特殊封闭曲线的效果。
4.2 光栅操作
光栅操作是指在进行绘图输出时,如何将要输出的象素点和屏幕上已有的象素点进行运算。最典型的运算是下面要讲到的 Alpha
混和。这里的光栅操作特指二进制的位操作,包括与、或、异或和直接的设置(覆盖)等等。应用程序可以利用
SetRasterOperation/GetRasterOperation
函数设置或者获取当前的光栅操作。这两个函数的原型如下(include/gdi.h):
|
4.3 内存 DC 和 BitBlt
新的 GDI 函数增强了内存 DC 操作函数。GDI 函数在建立内存 DC 时,将调用 GAL 的相应接口。如前所述,GAL
将尽量把内存 DC
建立在显示卡的显示内存当中。这样,可以充分利用显示卡的硬件加速功能,实现显示内存中两个不同区域之间位块的快速移动、复制等等,包括透明处理和
Alpha 混和。应用程序可以建立一个具有逐点 Alpha 特性的内存 DC(每个点具有不同的 Alpha 值),也可以通过
SetMemDCAlpha 设置内存 DC 所有象素的 Alpha 值(或者称为"Alpha 通道"),然后利用 BitBlt 和
StretchBlt 函数实现 DC 之间的位块传送。应用程序还可以通过 SetMemDCColorKey 函数设置源 DC
的透明色,从而在进行 BitBlt 时跳过这些透明色。
有关内存 DC 的 GDI 函数有(include/gdi.h):
|
CreateCompatibleDC 函数创建一个和给定 DC 兼容的内存 DC。兼容的含义是指,新创建的内存 DC 的象素格式、宽度和高度与给定 DC 是相同的。利用这种方式建立的内存 DC 可以快速 Blit 到与之兼容的 DC 上。
这里需要对象素格式做进一步解释。象素格式包含了颜色深度(即每象素点的二进制位数)、调色板或者象素点中 RGBA(红、绿、蓝、Alpha)四个分量的组成方式。其中的 Alpha 分量,可以理解为一个象素点的透明度,0 表示完全透明,255 表示完全不透明。在 MiniGUI 中,如果颜色深度低于 8,则 GAL 会默认创建一个调色板,并且可以调用 SetPalette 函数修改调色板。如果颜色深度高于 8,则通过四个变量分别指定象素点中 RGBA 分量所占的位。如果是建立兼容 DC,则兼容内存 DC 和给定 DC 具有一样的颜色深度,同时具有一样的调色板或者一样的 RGBA 分量组成方式。
如果调用 CreateMemDC 函数,则可以指定新建内存 DC 的高度、宽度、颜色深度,以及必要的 RGBA 组成方式。在 MiniGUI 中,是通过各自在象素点中所占用的位掩码来表示 RGBA 四个分量的组成方式的。比如,如果要创建一个包含逐点 Alpha 信息的16 位内存 DC,则可以用每分量四个二进制位的方式分配 16 位的象素值,这样,RGBA 四个分量的掩码分别为:0x0000F000, 0x00000F00, 0x000000F0, 0x0000000F。
ConvertMemDC 函数用来将一个任意的内存 DC 对象,根据给定的参考 DC 的象素格式进行转换,使得结果 DC 具有和参考 DC 一样的象素格式。这样,转换后的 DC 就能够快速 Blit 到与之兼容的 DC 上。
SetMemDCAlpha 函数用来设定或者取消整个内存 DC 对象的 Alpha 通道值。我们还可以通过 MEMDC_FLAG_RLEACCEL 标志指定内存 DC 采用或者取消 RLE 编码方式。Alpha 通道值将作用在 DC 的所有象素点上。
SetMemDCColorKey 函数用来设定或者取消整个内存 DC 对象的 ColorKey,即透明象素值。我们还可以通过 MEMDC_FLAG_RLEACCEL 标志指定内存 DC 采用或者取消 RLE 编码方式。
内存 DC 和其他 DC 一样,也可以调用 GDI 的绘图函数向内存 DC 中进行任意的绘图输出,然后再 BitBlt 到其他 DC 中。下面的程序段演示了如何使用内存 DC 向窗口 DC 进行透明和 Alpha 混和的 Blitting 操作:
|
4.4 增强的 BITMAP 操作
新的 GDI 函数增强了 BITMAP 结构,添加了对透明和 Alpha 通道的支持。通过设置
bmType、bmAlpha、bmColorkey 等成员,就可以使得 BITMAP 对象具有某些属性。然后可以利用
FillBoxWithBitmap/Part 函数将 BITMAP 对象绘制到某个 DC 上。你可以将 BITMAP
对象看成是在系统内存中建立的内存 DC 对象,只是不能向这种内存 DC
对象进行绘图输出。下面的示例程序从图象文件中装载一个位图对象,然后设置透明和 Alpha 通道值,最后使用 FillBoxWithBitmap
函数输出到窗口 DC 上:
|
你也可以通过 CreateMemDCFromBitmap 函数将某个 BITMAP 对象转换成内存 DC 对象。该函数的原型如下(src/gdi.h):
|
需要注意的是,从 BITMAP 对象创建的内存 DC 直接使用 BITMAP 对象中的 bmBits 所指向的内存,该内存存在于系统内存,而不是显示内存中。
和 BITMAP 相关的 MYBITMAP 结构,新的 GDI 也做了一些增强。MYBITMAP 可以看成是设备无关的位图结构,你也可以利用 CreateMemDCFromMyBitmap 函数将一个 MYBITMAP 对象转换成内存 DC。该函数的原型如下(src/gdi.h):
|
需要注意的是,许多 GAL 引擎不能对系统内存到显示内存的 BitBlt 操作提供硬件加速,所以,FillBoxWithBitmap 函数,以及从 BITMAP 对象或者 MYBITMAP 对象创建的内存 DC 无法通过硬件加速功能快速 BitBlt 到其他 DC 上。如果希望达到这样的效果,可以通过预先创建的建立于显示内存中的 DC 进行快速的 BitBlt 运算。
4.5 新的 GDI 绘图函数
除了光栅操作意外,还添加了一些有用的 GDI 绘图函数,包括 FillRect、FillCircle 等等,我们将在接下来的开发中,将继续添加诸如椭圆、圆弧、三次样条曲线、多边形填充等高级绘图函数。目前新增的 GDI 函数有:
|
尽管在 1.1.0Pre4 以及其后版本对 MiniGUI 的 GAL 和 GDI 进行了大规模的改造,但在新版本中仍然可以利用老的
GAL 和 GDI 接口,从而提供对低端显示设备的支持。需要注意的是,虽然新 GDI API
当中的许多结构和函数具有相同的名称,但某些函数已经被重新定义。所以,在编写应用程序的时候,要特别注意这一点。比如:新的 mde
演示程序当中,就利用了在
#include
#include
#include
......
#ifdef _USE_NEWGAL
SetRasterOperation (hdc, ROP_XOR);
FillRect (hdc, 0, 0, 200, 200);
#else
/* Not implemented */
#endif
......
本文重点介绍了在 MiniGUI 1.1.0 版本开发过程中新增的 GAL、GDI 功能和接口。新的 GAL 和
GDI重点针对高端图形应用进行了优化和功能增强,其中包括透明处理、Alpha 混和等高级特性,并且能够对硬件加速功能提供良好支持。本文分别就
GAL 和 GDI 的关系、GAL 的功能特性、GDI 的增强接口等方面较为全面地介绍了新的 GAL 和 GDI
接口。希望能够对程序开发有所帮助。
魏永明(),男,27 岁,工学硕士。国内最有影响的自由软件项目之一--MiniGUI 的创始人及主要开发人员。著有《Linux 实用教程》与《学用 Linux 与 Windows NT》,并主持翻译了《Red Hat Linux 奥秘》、《Linux 编程宝典》 等大量优秀的 Linux 技术著作。是清华大学 AKA Linux 编程技术系列讲座的主讲人。 |