对图形驱动程序的GDI支持
本章描述了Microsoft Windows NTÒ/Windows 2000图形设备接口(GDI),详细说明了GDI提供的对图形驱动程序的支持。

本书中术语“GDI”指的是核心模式GDI(也称作图形引擎);对MicrosoftÒ Win32Ò DDI的引用是显式的。核心模式GDI也称作图形引擎。

在线Windows 2000 DDK Graphics Driver Reference中记录了GDI函数和结构参考。大多数GDI函数声明和结构定义在winddi.h中。对于显示器驱动程序,DirectDraw堆管理器函数在dmemmgr.h中声明。这两个文件都和Windows 2000 DDK一起发布。



2.1 从驱动程序的观点看GDI

GDI是Windows NTÒ/WindowsÒ 2000图形驱动程序和应用之间的中介支持。应用程序调用Win32Ò GDI函数进行图形输出请求,这个请求通过核心模式GDI发送。然后核心模式GDI把这些请求发送到相应的图形驱动程序,如显示器驱动程序或打印机驱动程序。核心模式GDI是一个不能被替代的系统提供的模块。

GDI通过一系列设备驱动程序接口(DDI)函数和图形驱动程序通信。这些函数用其前缀Drv标识。信息通过这些入口点的输入/输出参数在GDI和驱动程序之间传递。驱动程序必须支持某些DrvXxx函数用于GDI调用。在返回GDI之前,驱动程序通过执行在其相关硬件上相应的操作来支持GDI请求。

GDI本身包括许多图形输出能力,去除驱动程序中支持这些能力的需求就能减小驱动程序的大小。GDI也输出驱动程序能够调用的服务函数,进一步减小了驱动程序必须提供支持的图形输出能力。GDI服务函数用其Eng前缀标识,而提供访问GDI维护的结构的函数用XxxOBJ_Xxx的形式命名。

图2.1显示了这个通信流。





图2.1 图形驱动程序和GDI的相互作用



2.1.1 作为应用图形语言的GDI

Win32 GDI和图形引擎都是完全与设备无关的。因此,应用不需要直接访问硬件。基于一个应用图形请求,GDI与设备无关的驱动程序一起工作,为一组图形设备提供高品质的图形输出。打印和显示设备使用相同的GDI代码路径。



2.1.2 作为绘制引擎的GDI

对于绘图操作,驱动程序首先必须对每个已经有效的PDEV结构启用一个表面。PDEV是一个物理设备的逻辑表示。如果硬件能够用GDI标准格式的位图建立,GDI就能用来进行一些或所有的位图表面的绘制。GDI也能处理高级的过渡调色技术。

对于启用PDEV和表面的信息,参考图形驱动程序参考中的DrvEnablePDEV和DrvEnableSurface函数。



2.1.2.1 GDI管理的位图

GDI全部用设备无关位图(DIB)格式管理位图,包括每个像素1位、4位、8位、16位、24位和32位。在这些位图上,GDI能进行所有的绘制直线、填充、文本输出以及位块传输(bitblt)操作。这使得驱动程序用GDI进行所有的图形绘制,或者使用实现函数都是可能的,因为硬件提供了特别支持。

如果设备在DIB格式中有帧缓冲区,GDI能够直接把一些或所有的图形输出到帧缓冲区,因而减小了驱动程序的大小。如果设备使用了非标准格式的帧缓冲区,驱动程序就必须实现所有要求的绘图函数。GDI还能模拟大多数绘图函数,尽管提高了性能上的代价:像素在被GDI操作之前必须拷贝到一个标准格式的位图中,并且在绘图完成后必须拷贝回原来的格式。



2.1.2.2 GDI管理的直线和曲线

GDI提供了改进的直线和曲线的定义。在DEVICE坐标中直线端点的坐标不要求是整数,就像Windows 3.x一样。这允许驱动程序不进行大致的取舍就传送图形对象。在GDI中基本的曲线是贝塞尔曲线(立方体锯齿)而不是一个椭圆。所有的GDI内部操作是用贝塞尔曲线处理的,它们被大多数高端的设备支持。对那些不处理贝塞尔曲线的设备,GDI在调用驱动程序绘制它们之前把曲线分割成直线段。

GDI能够下载用路径形式填充的区域,还有矩形的形式。驱动程序能够把路径分解成梯形或区间进行填充。



2.1.2.3 GDI管理的属性:画刷

GDI也管理所有的属性。GDI把属性作为画刷传递给驱动程序:驱动程序通过把画刷转换成有用的内部格式来实现它们。GDI为驱动程序维护这些转换信息。GDI还维护画刷所有的状态:包括范围、相关性、当前位置和线型。驱动程序能够缓存信息但不用来维护任何状态。除了初始化和画刷实现,GDI仅调用驱动程序在设备上绘图。在调用驱动程序之前,GDI关心转换、区域锁定以及指针与非操作。

当驱动程序要求使用还未实现的画刷,就需要回调GDI。GDI为画刷分配存储器并调用驱动程序来实现它,如果需要,可以进行抖动处理。



2.1.2.4 GDI过渡调色功能

GDI的过渡调色功能产生了高品质的抖动或颜色过渡调色映像,提供给没有内置这些功能的打印设备和显示设备。颜色过渡调色能提供:

§ 在给定的设备上提供最高品质的可再现的彩色和灰度级别

§ 在一组有限的强度级别上提高可视分辨率

§ 在不同的输出设备之间改进彩色相关性

传统的模拟过渡调色是一个使用过渡调色屏幕的单元过程。这个屏幕由相等大小的单元组成,中心到中心是固定的单元间隔。固定单元间隔调节墨水的浓度,而点的尺寸可以改变,用来产生连续色调的印记。

在计算机上大多数打印或屏幕阴影也使用固定单元的像素尺寸。为模拟点大小的变化,用一束像素的组合来模拟过渡调色屏幕。在Windows NTÒ/WindowsÒ 2000中,GDI包括提供一个好的第一近似的过渡调色缺省参数。额外的设备指定信息能加进系统以改进输出。



2.2 GDI/驱动程序的分工

为了理解图形驱动程序设计,弄懂GDI和驱动程序的角色以及它们如何协调是重要的。具有增强能力的GDI能够处理很多图形驱动程序预先要求的操作。GDI对于管理一些对图形操作很关键的数据结构,例如表面,也是有效的,尽管每个图形驱动程序必须访问它们。

2.2.1 GDI和驱动程序的通信

驱动程序对于GDI仅输出一个函数:DrvEnableDriver。所有其他的驱动程序支持的函数,包括DrvDisableDriver函数,是GDI通过一个指针数组来输出的。GDI调用DrvEnableDriver初始化驱动程序并返回驱动程序支持的DDI函数列表。因为有一些驱动程序必须支持的函数,所以GDI处理操作不包括在驱动程序的DrvEnableDriver例程的函数表中。当驱动程序被卸载时,GDI调用DrvDisableDriver。DDI函数在第3章“支持DDI”中深入讨论。

GDI使大量的服务对于驱动程序是可用的。这些服务分为两类:用户对象和服务例程。

2.2.1.1 GDI用户对象

GDI保护重要的内部数据结构,但通过把它们作为用户对象传递使驱动程序能访问这些结构的公共域。用户对象是中间数据结构,在GDI数据结构和需要访问这些结构内的信息的驱动程序之间提供了接口。驱动程序能把指向用户对象的指针传递回GDI,用以询问消息信息或请求各种服务。带有公共域的用户对象有下列优点:

§ 排除了直接访问内部GDI数据结构相关的问题。

§ 为驱动程序提供了一个空间保存GDI数据。例如,PATHOBJ结构能保存计算一个复杂对象(如路径)要求的所有额外数据。

下列用户对象是可用的:









对象
描述

BRUSHOBJ
为图形函数定义了画刷对象,输出直线、文本或填充。

驱动程序能调用BRUSHOBJ服务来实现画刷或找到GDI预先缓存的实现方法。

CLIPOBJ
为绘图或填充提供能访问裁剪区的驱动程序。这个区域能用一系列矩形计算。

FLOATOBJ
允许图形驱动程序模拟浮点操作。浮点操作不适用所有其他的核心模式驱动程序。

FONTOBJ
使驱动程序访问字体的一个特别的实例(或实现)的信息。

PALOBJ
包含RGB调色板颜色的结构;通过PALOBJ_cGetColors和DrvSetPalette函数可以访问。

PATHOBJ
定义路径指定要绘制什么(直线或贝塞尔曲线)。PATHOBJ结构传递给驱动程序用以描述要绘制或填充的一系列直线和贝塞尔曲线。

STROBJ
为驱动程序计算轮廓处理和位置的列表,描述如何绘制文本字符串。

SURFOBJ
识别一个表面,它可以是GDI位图、设备相关位图或设备管理的表面。更多的信息参见表面类型。

XFORMOBJ
描述一个任意的线性二维变换,如几何宽度直线(geometric wide line)。

XLATEOBJ
定义从源表面格式到目的表面格式转换像素所需要的变换。




2.2.1.2 GDI服务例程

GDI输出许多服务例程,其名字的形式是EngXxx。驱动程序动态地连接到win32k.sys来直接访问这些例程。GDI服务例程包括表面管理、绘图模拟以及路径、调色板、字体和文本服务。这些服务在GDI支持的服务中详细讨论。



2.2.2 PDEV协商

任何图形驱动程序的首要任务之一是在驱动程序初始化期间使PDEV有效。PDEV是物理设备的逻辑表现。这个表现由驱动程序定义,一般是私有的数据结构。启用PDEV的更多的信息参考DrvEnablePDEV。

通过DrvEnablePDEV函数,驱动程序必须给GDI提供信息,描述请求的设备及其能力。驱动程序给GDI的一条重要信息是DEVINFO结构的flGraphicsCaps和flGraphicsCaps2成员中的一组图形能力标志(GCAPS_Xxx和GCAPS2_Xxx标志)。

能力标志允许GDI确定那些操作是PDEV支持的。例如,GDI测试能力标志,指示在GDI尝试用这些基本的类型调用DrvStrokePath函数来绘制路径之前,PDEV是否能处理贝塞尔曲线和几何宽度直线。如果能力标志指示PDEV不能处理这些基本类型,GDI断开直线或曲线,使GDI能简化对驱动程序的调用。

从驱动程序一侧来看,无论何时驱动程序从GDI获得一个高级的路径相关的调用,如果路径或裁剪区对设备进行的处理过于复杂,它可返回 FALSE。

当驱动程序处理一条装饰线(cosmetic line)时它不能从DrvStrokePath返回FALSE,因为它必须为装饰线处理任意复杂的裁剪区或造型。然而,如果路径是贝塞尔曲线或几何直线,DrvStrokePath能够返回FALSE。当这种情况出现时,GDI把调用分割成简单的调用。就像能力标志位没有置1一样。例如,如果当DrvStrokePath发送一个几何直线时返回FALSE,GDI简化直线并调用DrvFillPath函数。

如果DrvStrokePath被报告一个错误,它必须返回DDI_ERROR。

在GDI和驱动程序之间的这种协商,对依赖于PDEV的函数,允许GDI和驱动程序产生高质量的输出而无须过多的通信。



2.2.3 表面协商

绘图和文本输出要求一个绘制的表面。这个表面由DrvEnableSurface函数创建并称作主表面(primary surface)。它也被称作屏幕上的表面(on-screen surface),因为它出现在视频显示器上。每个PDEV只能启用一个主表面,尽管一个驱动程序能够支持几个PDEV。支持DrvCreateDeviceBitmap函数的驱动程序能够创建和使用其他的表面。这些位图表面称作次要表面(secondary surface)或屏幕外的表面(off-screen surface)。对任一种类型的表面,驱动程序负责确定它支持的绘图操作的类型。



2.2.3.1 表面坐标

设备表面是228*228像素数组的子集。这些像素是由一对28位的带符号数寻址的。设备表面左上角的像素坐标是(0,0)。设备表面位于这个坐标空间的右下象限,两个坐标都是非负的。



2.2.3.2 DC原点

应用程序要求在227*227像素的数组范围内保存其图形。设备空间在DDI级有其他的尺寸,因为窗口管理器可能用一个带符号的27位的坐标即DC原点偏移应用程序的坐标。DC原点对驱动程序是不可见的,驱动程序在偏移执行之后才识别图形坐标。



2.2.3.3 FIX坐标

DDI使用分数坐标,能够在设备表面上1/16像素的范围内表示一个位置。(在矢量设备上,分数坐标比设备分辨率精确16倍。)分数坐标用32位数字表示,是带符号的28.4位FIX表示法。在这种表示法中,高28位表示坐标的整数部分,最低的4位表示分数部分。例如,0x0000003C等于+3.7500,0xFFFFFFE8等于-1.5000。

FIX坐标表示直线和贝塞尔曲线的控制点。对某一对象,如矩形裁剪区,GDI用带符号的32位整数表示坐标。因为坐标是28位数,整数坐标最高的5位或者全清0或者全置1。



2.2.3.4 表面类型

表面类型在如何处理它们的上下文中可以看到。这些类型如下:

§ 引擎管理的表面

§ 设备管理的表面(标准格式位图)

§ 设备管理的表面(非标准表面)

引擎管理的表面

引擎管理的表面有以下特征:

§ 由GDI创建和管理。

§ 用一种标准的DIB格式作为DIB创建:从上至下,原点位于左上角,或者从底向上,原点位于左下角。

§ 类型为STYPE_BITMAP。

§ 表面没有相应的设备句柄。

标准格式位图是单平面、压缩像素(每个像素的数据用连续的方式存储)格式的位图。位图的每条扫描线在4字节的边界排列。

在EngCreateBitmap函数中创建的位图是DIB格式。为了使引擎能管理位图,必须是DIB格式。



设备管理的表面(标准格式位图)

设备管理的表面有以下特征:

§ 通过对设备驱动程序的DrvCreateDeviceBitmap函数的调用创建。

§ 有一个表面的相关设备句柄(DHSURF;参见在线DDK Graphics Driver Reference中的SURFOBJ。)

§ 可以是透明的或不透明的。

不透明的设备管理表面是一种GDI既没有任何有关位图格式的信息,也没有位图中位的参考信息的表面。因为这些原因,驱动程序最少必须支持DrvBitBlt、DrvTextOut和DrvStockePath函数。这样的表面的类型是STYPE_DEVICE。

透明的设备管理表面是一种GDI含有有关位图格式的信息并知道位图中位的位置的表面。因为这个原因,驱动程序不需要实现任何绘图操作,并使它们都服从GDI。这样的表面的类型是STYPE_BITMAP。

驱动程序为了转换不透明的位图到透明的位图,它必须调用EngModifySurface函数。通过这一调用,驱动程序通知GDI位图格式和在存储器中位图的位置。

设备管理的DIB表面允许驱动程序回调GDI使GDI在表面绘图。管理其自身表面的驱动程序,也能通过在其表面周围封装DIB(用EngCreateBitmap创建)而引用到GDI的回调,使用DIB除外。



设备管理的表面(非标准格式位图)

通过调用EngCreateDeviceSurface函数使GDI创建表面并返回一个句柄,驱动程序可以启用一个设备管理的非DIB表面。GDI依赖驱动程序访问和控制绘制到何处,并从设备管理的表面读出。

设备相关位图(DDB),有时称作设备格式位图,是另一种类型的非DIB、设备管理的表面。DDB支持某些驱动程序,如VGA驱动程序,实现快速的位图到屏幕的块传送。DDB也允许驱动程序在屏幕外的显示存储器绘制非DIB位图。如果请求了DDB,驱动程序能支持DrvCreateDeviceBitmap函数并调用EngCreateDeviceBitmap函数使引擎返回一个到位图的句柄。



2.2.3.5 GDI彩色空间转换

GDI使用三个RGB颜色空间描述它的位图。在每个颜色空间中,三个位域,或颜色通道,在给定的颜色中分别用来指定红、绿、蓝使用的位的数量。为了能匹配GDI的位图能力,显示器驱动程序必须能从一个RGB颜色空间转换到另一个。

GDI能识别下列的颜色空间。

§ 5,5,5RGB:红、绿、蓝都是5位颜色通道。

§ 5,6,5RGB:红色是5位颜色通道,绿色是6位颜色通道,蓝色是5位颜色通道。

§ 8,8,8RGB:红、绿、蓝都是8位颜色通道。

通常,当从一个多位的颜色通道向少位的颜色通道转换时,GDI丢弃掉低位。当从一个少位的颜色通道向多位的通道转换时,较小通道的所有位全部拷贝到较大的通道。为了填充较大通道的剩余位,较小通道的某些位将再次拷贝到较大的通道。下表概述了GDI从一个RGB颜色空间转换到另一个所使用的规则。在这个表中,转换过程中值发生改变的颜色通道用黑体表示。

GDI颜色空间转换规则

From
To
规则
例子

5,5,5
5,6,5
源的绿色通道的最高有效位(MSB)加到目标的绿色通道的低位最后。
(0x15,0x19,0x1D)变成(0x15,0x33,0x1D)。

注意只有绿色通道改变。

源的5位通道的值是二进制11001,转换成6位值,110011。

5,5,5
8,8,8
对每个通道,源通道的3个MSB加到目标通道的最低位的最后。
(0x15,0x19,0x1D)变成(0xAD,0xCE,0xEF)。

在红色通道中,10101变成10101101。类似的变化也出现在绿色和蓝色通道。

5,6,5
5,5,5
丢弃源绿色通道的最低有效位(LSB)。
(0x15,0x33,0x1D)变成(0x15,0x19, 0x1D)。

注意只有绿色通道改变。

丢弃110011的最低位,得到11001。

5,6,5
8,8,8
对源的5位通道(红色和蓝色),从源通道拷贝3个MSB加到目标通道的最低位的最后。对6位的绿色通道,从源通道拷贝2个MSB加到目标通道的最低位的最后。
(0x15,0x33,0x1D)变成(0xAD,0xCE,0xEF)。

在红色通道中,10101变成10101101。在绿色通道中,110011变成11001111。蓝色通道的变化和红色通道类似。

8,8,8
5,5,5
丢弃源通道的3个最低有效位(LSB)。
(0xAB,0xCD,0xEF)变成(0x15,0x19,0x1D)。

在红色通道中,10101101变成10101。类似的变化也出现在其他两个通道。

8,8,8
5,6,5
丢弃红色和蓝色通道的3个最低有效位(LSB)。丢弃绿色通道的2个最低有效位(LSB)。
(0xAB,0xCD,0xEF)变成(0x15,0x33,0x1D)。

在绿色通道中,11001101变成110011。红色和蓝色通道的变化与前面列出的变换相同。




2.2.3.6 Hooking和Punting

术语Hooking和Punting指的是驱动程序决定是否提供标准的位图绘画操作,或依赖GDI提供这些操作。如果驱动程序实现了引擎管理的表面,GDI能处理所有的绘图操作。然而,如果硬件能加速这些操作,驱动程序能提供一个或更多的绘图函数。通过实现,或Hooking DrvXxx函数来做到这一点。

也许只想实现绘图操作的一个子集,实现一个特殊的DDI接口点。对它不支持的任何操作,驱动程序能调用相应的GDI函数来实现。这称作Punting到GDI。有一些情形是操作必须在驱动程序内实现。例如,如果驱动程序实现了一个设备管理的表面,某些绘图函数必须在显示器驱动程序内完成。

Hooking

缺省情况下,当绘图表面是引擎管理的表面时,GDI处理绘画(绘图)操作。驱动程序利用硬件对一给定的表面,为一些或所有的绘图函数提供了加速,或者使用了特别的块传送硬件,能够hook这些函数。对于hook调用,驱动程序把hook指定为EngAssociateSurface和EngModifySurface函数flHook参数的标记。

如果驱动程序指定了一个函数的hook标记,它必须提供在其支持DDI入口点的列表中的函数。驱动程序能够优化具有硬件支持的操作。这样的驱动程序在一个hook调用中可能只能处理某一种情况。例如,如果在一个hook调用中请求了复杂的图形,它可能还要更有效地直接回调GDI,允许GDI处理操作。

这里还有另一个例子,驱动程序选择是否处理hook调用。考虑应该支持硬件的驱动程序,有能力用某些ROP处理位块传输调用。即使驱动程序能够独立地实现许多操作,其他方面仅是一个缓冲区。这样的驱动程序将为帧缓冲区给位图表面返回一个句柄,就像为其PDEV表面一样,但它将为自己hook DrvBitBlt调用。当GDI调用DrvBitBlt时,驱动程序能够检查ROP来看它是否是由硬件支持的一个函数。如果不是,驱动程序能通过对EngBitBlt的一个调用把操作传递GDI。

支持设备管理表面的驱动程序必须向外hook一些绘图函数,名字是DrvCopyBits、DrvTextOut和DrvStrokePath。虽然GDI模拟能够处理其他绘图函数,因为性能上的原因推荐这种类型的驱动程序hook其他函数,就像DrvBitBlt和DrvRealizeBrush函数,因为模拟需要从或向表面绘图。



Punting

Punting回调到GDI的意思是提交一个调用到相应的GDI模拟。通常,对每个DrvXxx调用都有一个相应的GDI EngXxx模拟调用,带有相同的参数。在驱动程序制作透明的位图时,所有的参数都没有改变地传递到GDI模拟。对每个调用驱动程序punt回GDI,驱动程序的大小缩减了(因为功能上的代码忽略了)。然而,因为引擎拥有调用,驱动程序在执行速度上没有控制。对一些复杂的情况,在驱动程序中提供支持也许没有实际的优势。



可以hook的GDI图形输出函数

驱动程序能够hook的图形输出函数和相应的GDI模拟在下表中列出。

驱动程序图形输出函数
相应的GDI模拟

DrvBitBlt
EngBitBlt

DrvPlgBlt
EngPlgBlt

DrvStretchBlt
EngStretchBlt

DrvStretchBltROP
EngStretchBltROP

DrvTextOut
EngTextOut

DrvStrokePath
EngStrokePath

DrvFillPath
EngFillPath

DrvStrokeAndFillPath
EngStrokeAndFillPath

DrvLineTo
EngLineTo

DrvCopyBits
EngCopyBits

DrvAlphaBlend
EngAlphaBlend

DrvGradientFill
EngGradientFill

DrvTransparentBlt
EngTransparentBlt




2.3 GDI支持的服务

GDI输出许多服务例程,能简化驱动程序的设计。驱动程序能够直接调用这些例程。通常图形引擎服务例程的名字以Eng开头。与特殊的对象相关的服务例程总是用对象的名字开头;例如,CLIPOBJ_cEnumStart是一个CLIPOBJ服务。

注意 第一个参数是用户对象的指针的任务例程,是用户对象的方法和使用通常的C++惯例调用。因此,用C++写的驱动程序能作为方法访问服务例程。

这些服务例程有以下几类:

§ 表面管理

§ 调色板服务

§ 路径服务

§ 绘图服务

§ 字体和文本服务

第3章“支持DDI”描述了DDI的入口点,并解释许多这些服务例程能用来帮助驱动程序实现入口点。每个服务函数的详细描述参见在线DDK。



2.3.1 GDI对表面的支持

对每个PDEV,驱动程序必须支持DrvEnableSurface函数。DrvEnableSurface建立要绘制的表面并将其和PDEV相关。驱动程序也必须支持DrvDisableSurface函数停止创建的表面。因为GDI创建和维护表面,驱动程序依赖几个GDI服务函数(在下页的表中列出)实现启用和禁止表面。



函数名
用途

EngAssociateSurface
用PDEV相关一个表面并定义驱动程序编写者要hook的那个表面的绘图操作。它使用PDEV缺省的调色板和方式步骤。驱动程序在DrvEnableSurface的执行过程中必须对主表面进行调用。当驱动程序在锁定表面进行写之前启用第二个表面时,也必须进行这个调用。

EngCheckAbort
(仅针对打印机)使打印机驱动程序能够测定打印机的工作是否已经结束。

EngCreateBitmap
创建一个标准格式DIB。在这种类型表面上GDI能够执行所有绘图操作。

EngCreateDeviceBitmap
创建一个DDB,驱动程序在上面绘图是可靠的(虽然也可创建一个DIB,在这种情况下驱动程序能够回调以使GDI在上面绘图。

EngCreateDeviceSurface
创建一个设备管理表面。驱动程序为这个表面管理某些绘图操作是可靠的。此函数又返回一个驱动程序管理句柄。

EngDeleteSurface
删除一个表面(DIB,DDB,或设备管理表面)

EngEraseSurface
在表面上用给定的颜色填充指定的矩形,有效地清除表面。调用这个函数仅可清除一个GDI位图表面。

EngLockSurface
通过创建表面的一个用户对象(SURFOBJ)使驱动程序访问已创建的表面。(源表面是不锁定的。)

EngMarkBandingSurface
(仅针对打印机)标记表面为相关的表面。

EngUnlockSurface
当驱动程序已完成一项绘图操作时释放一个表面(禁止第二个表面时调用此函数)




这些函数更详细的内容,请参考在线DDK。



2.3.2 GDI支持的调色板

GDI可以做大多数有关调色板管理的工作。当GDI调用DrvEnablePDEV函数,驱动程序把缺省的调色板作为DEVINFO结构的一部分返回到GDI。驱动程序必须用EngCreatePalette函数创建这个调色板。

调色板有效地把32位颜色索引映射到24位RGB颜色值,这是GDI使用调色板的方法。驱动程序指定其调色板,这样GDI能确定不同的颜色索引如何在设备上出现。

驱动程序只要使用GDI提供的XLATEOBJ,就不需要处理大多数调色板操作和计算。

如果设备支持可改变的调色板,必须实现DrvSetPalette函数。当应用为设备改变调色板并把作为结果的新调色板传递给驱动程序时,GDI调用DrvSetPalette。驱动程序要设置内部的硬件调色板,尽可能地匹配新调色板。

可以用下表列出的两种格式为GDI定义调色板。

调色板格式
描述

Indexed
一个颜色索引是RGB值的数组的一个索引。这一数组可以是小的,例如,包括16个颜色索引;或者是大的,例如,包括4096个颜色索引,甚至更多。

Bit Fields
颜色索引里的位域依据每一种颜色里R、G和B的数量指定颜色。例如,5位能够用来为每一种颜色提供0和31之间的一个值。当转换为RGB时,每个部分的5位的值将放大到包括0~255的范围。(通常RGB代表自己是由位域定义的)




相反,GDI一般使用调色板映射。也就是说,应用指定一个RGB颜色进行绘图,并且GDI必须指定设备显示的颜色索引的地址。就像下表指出的,GDI提供两种主要的调色板服务函数用来创建和删除调色板,以及一些与PALOBJ和XLATEOBJ有关的服务函数用于在两个调色板之间转换颜色索引。

函数
描述

EngCreatePalette
创建一个调色板。驱动程序通过给DEVINFO结构里的调色板返回一个句柄使设备和调色板相联系。

EngDeletePalette
删除给定的调色板。

PALOBJ_cGetColors
允许驱动程序从从一个索引的调色板下载RBG颜色。它由显示驱动程序在DrvSetPalette函数中调用。

XLATEOBJ_iXlate
从一个源颜色索引转换到目的颜色索引

XLATEOBJ_piVector
从一个索引的源调色板中检索转换向量。驱动程序能使用这个向量完成其自身从源索引到目的索引的转换。

XLATEOBJ_cGetPalette
在一个索引的源调色板中检索24位RGB颜色或颜色的位域格式驱动程序能使用这个函数从调色板获得信息执行颜色混合。




这些函数更详细的内容,请参考在线DDK。



2.3.3 路径的GDI服务

为帮助矢量设备填充复杂的区域,驱动程序能调用创建、修改和计算路径的引擎函数;这些函数在下表列出。驱动程序通过PATHOBJ结构访问路径。

GDI路径服务函数
描述

EngCreatePath
为驱动程序的临时使用分配一个路径。驱动程序在从当前的绘图调用返回GDI之前要删除这个路径。

EngDeletePath
删除通过EngCreatePath函数创建的路径。

PATHOBJ_vGetBounds
返回路径的一个混合矩形。

PATHOBJ_vEnumStart
通知PATHOBJ驱动程序将调用PATHOBJ_bEnum用指定的路径计算曲线。这个函数假设计算重新开始时必须要调用。

PATHOBJ_bEnum
从路径检索下一个PATHDATA记录。每个记录描述了一个子路径的全部或部分。

PATHOBJ_vEnumStartClipLines
允许驱动程序请求相对一个PATHOBJ要裁剪的直线。当裁剪区比一个矩形更复杂时是有用的。

PATHOBJ_bEnumClipLines
从路径计算已裁剪的直线段

PATHOBJ_bMoveTo
在一个已定义的PATHOBJ路径里改变现有的位置

PATHOBJ_bPloyLineTo
在一个已定义的PATHOBJ路径里绘制直线

PATHOBJ_bPloyBezierTo
在一个已定义的PATHOBJ路径里绘制贝塞尔曲线

PATHOBJ_bCloseFigure
通过正绘制的一条直线回至起始点关闭路径


这些函数更详细的内容,请参考在线DDK。



2.3.4 GDI绘图服务及其他

为了支持CLIPOBJ,BRUSHOBJ,和XFORMOBJ结构,GDI提供几种绘图服务(在下页的表中列出)此外GDI模拟在前面hooking对punting中描述。

GDI绘图服务函数
描述

EngCreateClip
为驱动程序的临时使用分配一个CLIPOBJ。当不再需要它时驱动程序调用EngDeleteClip函数删除它。

EngDeleteClip
用 EngCreateClip函数删除已分配的CLIPOBJ

EngBitBlt
DrvBitBlt函数的GDI模拟

EngCopyBits
DrvCopyBits函数的GDI模拟

EngStretchBlt
DrvStretchBlt函数的GDI模拟

EngFillPath
DrvFillPath函数的GDI模拟

EngStrokeAndFillPath
DrvStrokeAndFillPath函数的GDI模拟

EngStrokePath
DrvStrokePath函数的GDI模拟

EngLineTo
DrvLineTot函数的GDI模拟

BRUSHOBJ_pvAllocRbrush
为实现驱动程序的画刷分配存储器。

BRUSHOBJ_pvGetRbrush
为实现驱动程序的画刷返回一个指针;如果还没有实现画刷就实现画刷。

CLIPOBJ_cEnumStart
在已裁剪的全部或部分区域里为矩形的计算设定参数。(没有调用这个函数时能够计算一次这个区域,但是随后的计算需要使用这个函数。)

CLIPOBJ_bEnum
从裁剪区域恢复大量矩形。

CLIPOBJ_ppoGetPath
作为路径用来恢复复杂的区域。


这些函数更详细的内容,请参考在线DDK。



2.3.5 GDI字体和文本服务

GDI提供对字体管理和文本输出的支持。FONTOBJ结构和相关函数允许驱动程序访问一个字体的特定实例。为了支持文本输出,驱动程序访问STROBJ结构和相关函数。下表列出了FONTOBJ和STROBJ相关的函数。

函数
描述

EngT

ExtOut
GDI模拟DrvTextOut函数

FONTOBJ_cGetAllGlyphHandles
允许驱动程序恢复GDI字体的每一个字形句柄。驱动程序使用这个服务下载全部字体。

FONTOBJ_vGetInfo
返回描述已分配字体的信息。

FONTOBJ_cGetGlyphs
为字体使用者把字形句柄翻译成指针给已分配的字形数据。到下一次调用FONTOBJ_cGetGlyphs之前这些指针均有效。

FONTOBJ_pQueryGlyphAttrs
返回有关字体字形的信息。

FONTOBJ_pxoGetXform
为相关的字体恢复从抽象到设备的转换。这个转换要求驱动程序实现一个驱动程序提供的字体。

FONTOBJ_pifi
取得一个到描述相关字体的IFIMETRICS结构的指针。

FONTOBJ_pvTrueTypeFontFile
取得一个到与TrueType字体相关的ROM映射TrueType文件的指针。

STROBJ_vEnumStart
为指定的STROBJ结构重新计算GLYPHPOS数组。驱动程序要在随后的计算之前调用这个函数。

STROBJ_bEnum
在指定的STROBJ中计算字体轮廓一致性和位置。

STROBJ_dwGetCodePage
返回与指定的STROBJ相关的代码页。


这些函数更详细的内容,请参考在线DDK。



2.3.6 GDI支持的服务及其他

GDI给驱动程序编写者提供了多种一般的支持服务,包括装载、读取、操作数据文件的能力,以及分配内核模式和用户模式的存储器。



2.4 浮点数支持

内核模式图形驱动程序在调用GDI提供的EngSaveFloatingPointState和EngRestoreFloatingPointState 例程之间必须进行所有的浮点操作。

如果硬件有一个浮点处理器,驱动程序能够直接做浮点操作。另外,驱动程序能使用GDI的FLOATOBJ服务来计算浮点操作。不考虑处理器类型,当声明浮点值时,驱动程序要使用FLOAT数据类型。



2.5 数据类型

下表中定义的数据类型在设备驱动程序接口里出现。这些数据类型中的几个在前面GDI用户对象里描述过。指针型数据类型用星号(*)标记。



DDI数据类型
变量前缀名
定义

BOOL
b
可以是TRUE或FALSE的32位值

BYTE
j
8位无符号整数

BRUSHOBJ*
pbo
指向画刷对象的指针

CLIPLINE
cl
裁剪线对象

CLIPOBJ
pco
裁剪对象的指针

DHPDEV
dhpdev
由设备驱动程序定义的32位句柄。它识别一个物理设备。

DHSURF
dhsurf
由设备驱动程序定义的32位句柄。它识别一个设备管理表面。

FIX
fix
定点数

FLOATL
e
浮点数

FLOAT-LONG
el
32位溢出值,依据上下文解释成LONG或FLOAT

FLONG
fl
32位标志的设定

FONTOBJ*
pfo
字体对象的指针

FSHORT
fs
16位标志的设定

HBM
hbm
由GDI定义能识别位图的32位句柄

HPAL
hpal
由GDI定义能识别调色板的32位句柄

HSURF
hsurf
由GDI定义能识别表面的32位句柄

LONG
l
32位有符号整数

MIX
mix
32位数量,它的低16位定义前景和背景的混合模式

PALOBJ*
ppalo
调色板对象指针

PATHOBJ*
ppo
路径对象指针

POINTE
pte
由{FLOAT x,y;}组成的小数点结构

POINTFX
ptfx
由{FIX x,y;}组成的小数点结构

POINTL
ptl
由{LONG x,y;}组成的小数点结构

PWSZ
pwsz
以0结束的Unicode字符串的指针

PVOID
pv
没有定义数据类型的VOID指针

RECTL
rcl
由{LONG xLeft,yTop,xRight,yBottom;}组成的矩形结构

RECTFX
rcfx
由{FIX xLeft,yTop,xRight,yBottom;}组成的矩形结构

ROP4
rop4
指定如何混合源、目标、图形以及屏蔽像素的32位值

SHORT
s
16位有符号整数

SIZEL
sizl
由{ULONG Cx,Cy;}组成的二维结构

STROBJ*
pstro
文本字符串对象指针

SURFOBJ*
pso
表面对象指针

ULONG
ul
32位无符号整数

USHORT
us
16位无符号整数

XFORMOBJ*
pxo
坐标转换对象指针

XLATEOBJ*
pxlo
颜色转换对象指针




下表中列出的参数前缀用于修改它们使用的变量名前缀。



前缀
参数用途

i
已计算的索引

c
计数

p
指针